zoukankan      html  css  js  c++  java
  • PHP trait与单例模式 (一次编写,到处使用)

    一  trait

      php是单继承的语言,无法同时从两个基类中继承属性和方法,为了解决这个问题,php出了Trait这个特性.

    个人理解的trait是: trait = abstract class - interface,其中拥有interface的多个继承的性质.'继承'的方式是 use trait;

    二  单例模式

      单例模式确保类在全局只能有一个实例,因为它的实例是由自己保存,在类的外部也无法对该类进行实例化.PHP的单例模式是为了避免重复创建对象带来的资源消耗.

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    实际项目中像数据库查询,日志输出,全局回调,统一校验等模块。这些模块功能单一,但需要多次访问,如果能够全局唯一,多次复用会大大提升性能。

     

    • 单例类只能有一个实例
    • 单例类必须自己创建自己的唯一实例
    • 单例类必须给所有其他对象提供这一实例

    三   trait与单例模式结合使用

      3.1 简单demo

        

    trait Singleton
    {
        private static $instance;
    
        static function getInstance(...$args)
        {
            if(!isset(self::$instance)){
                self::$instance = new static(...$args);
            }
            return self::$instance;
        }
    }
    
    class MySingleton
    {
        use Singleton;
    }
    
    $mySingleton = Mysingleton::getInstance();

      3.2 为什么不用 new self()

      new self() 和 new static 的区别: 只有在继承中才能体现出来、如果没有任何继承、那么二者没有任何区别 然后 new self() 返回的实列是不会变的,无论谁去调用,都返回的一个类的实列, 而 new static则是由调用者决定的。

      此处如果用new self() ,那么我们获取到的对象就不是MySingleton了

      3.3 类,基类,trait之间同名函数的优先级

      先说结论,类 > trait > 基类,简单实例:

    <?php
    trait Dog{
        public $name="dog";
        public function drive(){
            echo "This is dog drive";
        }
        public function eat(){
            echo "This is dog eat";
        }
    }
    
    class Animal{
        public function drive(){
            echo "This is animal drive";
        }
        public function eat(){
            echo "This is animal eat";
        }
    }
    
    class Cat extends Animal{
        use Dog;
        public function drive(){
            echo "This is cat drive";
        }
    }
    $cat = new Cat();
    $cat->drive();
    echo "<br/>";
    $cat->eat();
    
    ?>
    得出:

    This is cat drive This is dog eat

      3.4 特殊情况,基类use trait,本类不use

    trait A{
        private static $instance;
        static function getInstance()
        {
            if(!isset(self::$instance)){
                self::$instance = new static();
            }
            return self::$instance;
        }
    }
    
    class B{
        use A;
        function a()
        {
            var_dump('call at B');
        }
    }
    
    class C extends B{
        function a()
        {
            var_dump('call at c');
            parent::a();
        }
    }
    
    class D extends B{
        use A;
        function a()
        {
            var_dump('call at D');
            parent::a(); 
        }
    }
    $b = B::getInstance();
    $c = C::getInstance();
    $d = D::getInstance();
    
    $c->a();
    $d->a();
    得出:

    string
    (9) "call at B" string(9) "call at D" string(9) "call at B"

      此时我们与疑问了,根据3.2所写,调用者是 C::getInstance();  怎么$c->a();像变成了 $b->a();一样呢???
    (个人观点,也验证了)其实这里的$c,就是class B

      接下来进行验证:

    trait A{
        private static $instance;
        static function getInstance()
        {
            if(!isset(self::$instance)){
                self::$instance = new static();
            }
            return self::$instance;
        }
    }
    
    class B{
        use A;function h(){
            var_dump('h call at b');
        }
    
    }
    
    class C extends B{function h(){
            var_dump('h call at c');
        }
    }$b = B::getInstance();
    $c = C::getInstance();$c->h();
    得出:

    string
    (11) "h call at b"

      而我们去掉 class c 中的 h(), 会没有打印,验证了 这里的$c,就是class B 这句话.

      本篇就讲这么多,有兴趣的可以更深入了解trait与单例模式的知识点.

  • 相关阅读:
    JDBC连接数据库
    Promise的基本用法
    Cookie、LocalStorage 与 SessionStorage的区别在哪里?
    判断时间大小,数值大小
    控制input文本框只能输入正整数
    利用layer弹框代替alert效果,且可以增加callback函数
    input 只能输入数字且控制位数
    递归函数
    分页插件,直接把返回值赋过去即可
    获取选中checkbox的value值
  • 原文地址:https://www.cnblogs.com/bushuwei/p/12030899.html
Copyright © 2011-2022 走看看