最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • PHP类的秘密(12) Trait的秘密

    正文概述 转载于:掘金(传达室老大爷)   2021-07-06   264

    Trait是一种在类中实现代码复制的方法.

    记住这句话, 你就掌握了Trait的精髓. Trait有很多特性和规则, 但归根结底都是这句话的应用和体现.

    定义Trait

    trait TezhengA {
        public function smallTalk() {
            echo 'a';
        }
        public function bigTalk() {
            echo 'A';
        }
    }
    
    class SK
    {
    use TezhengA
    }
    
    $kl=new SK
    $kl->smallTalk();   //'a'
    $kl->bigTalk();     //'A'
    

    上例就是最简单的trait定义和调用, 可以将class SK中的trait直接替换成它所包含的代码, 是没有问题的. 所以这就给开发者一个很简单的方式去复制代码, 只需要一个use语句即可!

    Trait和普通类定义有哪些区别呢

    主要是以下三点:

    首先, Trait不是类, 它只是一段可以被复用的代码.

    无法通过 trait 自身来实例化。因为它只是一段代码, 所以实例化没有意义.

    可以包含抽象方法, 要求让继承子类去定义抽象方法.

    trait Asd
    {
        abstract function Rew();
    }
    
    class BDS
    {
        use Asd;
        function Rew()
        {
       echo'abs'; // TODO: Implement Rew() method.
        }
    }
    $ls=new bds;
    var_dump($ls);
    

    可以看到除了抽象类以外, trait也可以定义抽象方法, 并要求使用的类去定义这些方法.

    除了以上3点区别以外, trait并没有什么特殊的地方, 它可以包含静态属性, 静态成员, 私有属性, 支持各种可见度.

    在使用trait时可能遇到的问题

    两个trait中有同名的方法:

    trait TezhengA {
        public function smallTalk() {
        echo 'a';
        }
        public function bigTalk() {
        echo 'A';
        }
    }
    
    trait TezhengB {
        public function smallTalk() {
        echo 'b';
        }
        public function bigTalk() {
        echo 'B';
        }
    }
    
    class Aliased_Talker {
    use TezhengA, TezhengB {
        TezhengB::smallTalk insteadof TezhengA;   //TezhengB::smallTalk优先于A
        TezhengA::bigTalk insteadof TezhengB;     //TezhengA::bigTalk优先于B
        TezhengB::bigTalk as talk;                //起别名;
    }
    }
    $as=new Aliased_Talker;
    $as->bigTalk();         //A
    $as->smallTalk();       //b
    $as->talk();      //B
    

    可以使用insteadof关键词指明替代关系, 或者使用as关键词起个别名. 问题解决.

    如果trait中的方法和父类重名怎么办?

    trait Counter1{
    function inc(){
        echo'father';
    }
    }
    
    class C1 {
    use Counter1;
    }
    
    class C2 extends C1{
    use counter1;
    function inc()
    {
        echo 'child';
    }
    }
    $o = new C2();
    $o->inc();    //child, 子类自己的方法优先
    

    子类也会继承父类的trait, 当方法名冲突时, 优先级: 当前类的成员 > trait 的方法 > 被继承的方法

    如果trait中使用了final, 会有什么影响?

    trait Fas {
        final public function hello($s) { print "$s, hello!"; }
    }
    class Bar {
        use Fas;
        final public function hello($s) { print "hello, $s!"; }      
    }
    class Cee extends Bar
    {
        public function hello($s) { print "hello!"; }    //报错, final在子类生效
        }
    

    可以看到, trait中的final关键词在class Bar并没有影响, 但是子类继承中, 却产生了影响.

    trait和类可以定义同名属性么?

    trait PropertiesTrait {
        public $same = true;
        public $different = false;
    }
    
    class PropertiesExample {
        use PropertiesTrait;
        public $same = true; // php 7.0.0 后没问题,之前版本是 E_STRICT 提醒
        public $different = true; // 致命错误
    }
    

    通过上例可以看到, 如果同名属性的值也一样, 则正常, 如果同名属性有不同的值, 则会报错.

    Trait使用中的一些技巧

    Trait可以进行嵌套, trait 也能够使用 trait, trait中所有方法名字不变, 如果两个trait有同名方法, 一样使用insteadof或as解决冲突

    trait Hello {
        public function sayHello() {
            echo 'Hello ';
    }
    }
    
    trait World {
        public function sayHello() {
            echo 'World!';
    }
    }
    
    trait HelloWorld {
        use Hello, World{
    World:: sayHello instead of Hello;
    }      //使用2个traits
    }
    
    class MyHelloWorld {
        use HelloWorld;      //调用helloworld
    }
    
    $o = new MyHelloWorld();
    $o->sayHello();          //可以直接调用子trait中的方法
    

    同时insteadof也可以用一个方法替代多个同名方法:

    class TalkerD {
        use AD, BD, CD {
        AD::sayHello insteadof BD, CD;
        AD::sayWorld insteadof BD, CD;               
        }
    }
    

    关键词as可以指定方法可见度:

      use HelloWorld { sayHello as protected; }
    

    特别注意

    当trait中含有静态属性时, 要注意静态属性的值, 因为不同类use trait时可能会有不同的值:

    trait Beer {
        protected static $type = 'Light';
        public static function printed(){
            echo static::$type.PHP_EOL;
        }
        public static function setType($type){
            static::$type = $type;
        }
    }
    
    class Ale {
        use Beer;
    }
    
    Beer::setType("Dark");   //通过trait直接调用方法
    
    class Lager {
        use Beer;
    }
    
    Beer::setType("Amber");  //通过trait直接调用方法
    
    Beer::printed();  // Prints: Amber
    Ale::printed();   // Prints: Light
        Lager::printed(); //Dark
        
    

    通过上例可以看到, trait可以直接调用自己的静态方法, 并修改自己的静态属性, 这样导致继承子类会有不同的属性值.

    感谢阅读, 如有不准确或错误请留言指正, 我会及时修正, 感谢!

    欢迎喜欢技术的小伙伴儿和我交流, 微信1296386616

    总结不易, 请勿私自转载, 否则别怪老大爷不客气!

    参考资料:

    www.php.net PHP官方文档


    起源地下载网 » PHP类的秘密(12) Trait的秘密

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元