美文网首页thinkphp程序员
萧峰与郭靖教你学会PHP的Trait

萧峰与郭靖教你学会PHP的Trait

作者: 闲睡猫 | 来源:发表于2017-07-22 23:54 被阅读41次

    自PHP5.4之前,PHP面向对象需要复用代码的方式是使用类的继承。但PHP只支持单继承,在应对较复杂的业务逻辑中,单继承就显得捉襟见肘了。

    trait的使用场景

    如以下应用场景:

    class Person {
        public function eat() {
            echo "我是人,我能吃饭<br />";
        }
    }
    
    class GuoJing extends Person {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    class XiaoFeng extends Person {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    萧峰

    Guojing 类 与 XiaoFeng 类都继承于Person,都有共同的 Kungfu 方法,显然,我们不能将这个 Kungfu 方法写到 Person 类,不然随便一个路人甲继承了 Person 类,就拥有了 Kungfu 技能。

    用Trait就能解决此问题:

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    class Person {
        public function eat() {
            echo "我是人,我能吃饭<br />";
        }
    }
    
    class GuoJing extends Person {
        use Tool;
    }
    
    class XiaoFeng extends Person {
        use Tool;
    }
    
    $guojing = new GuoJing();
    $xiaofeng = new XiaoFeng();
    
    $guojing->kungfu();
    $xiaofeng->kungfu();
    

    结果如下:

    降龙十八掌!
    降龙十八掌!
    

    方法/属性的重写

    如果Trait类、基类和本类中的方法或属性同名,最终会以哪个为准?

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    class Person {
        public function eat() {
            echo "我是人,我能吃饭<br />";
        }
    
        public function kungfu() {
            echo "不是每个人都会功夫<br />";
        }
    }
    
    class GuoJing extends Person {
        use Tool;
        public function kungfu() {
            echo "除了降龙十八掌,我还懂九阴真经!<br />";
        }
    }
    
    class XiaoFeng extends Person {
        use Tool;
    }
    
    $guojing = new GuoJing();
    $guojing->kungfu();
    

    结果:

    除了降龙十八掌,我还懂九阴真经!
    

    注释本类的 kungfu 方法,得出的结果是:

    降龙十八掌!
    

    当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法。

    组合多个trait

    多个trait有同名的方法/属性时,会报错:

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    trait Skill {
        public function kungfu() {
            echo "浑厚的内力修为<br />";
        }
    }
    
    class GuoJing {
        use Tool, Skill;
    }
    
    $guojing = new GuoJing();
    $guojing->kungfu();
    
    Fatal error: Trait method kungfu has not been applied, because there are collisions with other trait methods on GuoJing 
    

    解决方式:使用insteadof和as来解决冲突

    • insteadof: 使用某个方法替代另一个

    • as: 给方法取别名

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    trait Skill {
        public function kungfu() {
            echo "浑厚的内力修为<br />";
        }
    }
    
    class XiaoFeng {
        use Tool, Skill {
            Skill::kungfu insteadof Tool;
            Skill::kungfu as ability;
        }
    }
    
    $xiaofeng = new XiaoFeng();
    $xiaofeng->ability();
    
    浑厚的内力修为
    

    trait方法的访问控制

    as关键词可以修改方法的访问控制

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    class XiaoFeng {
        use Tool {
            Tool::kungfu as protected ability; // 修改方法的访问控制并起别名
        }
    }
    
    $xiaofeng = new XiaoFeng();
    $xiaofeng->ability();
    

    报错:

    Fatal error: Uncaught Error: Call to protected method XiaoFeng::ability() from context
    

    Trait组合

    Trait也能组合Trait,同时,Trait中支持抽象方法、静态属性、静态方法。

    <?php
    trait Tool {
        public function kungfu() {
            echo "降龙十八掌!<br />";
        }
    }
    
    trait Feature{
        use Tool;
        abstract public function dream();
        public static function character() {
            echo "磊落豪雄 <br />";
        }
    }
    
    class XiaoFeng {
        use Feature;
        public function dream() {
            echo "弄清楚:我是谁? <br />";
        }
    }
    
    $xiaofeng = new XiaoFeng();
    $xiaofeng->kungfu();
    XiaoFeng::character();
    $xiaofeng->dream();
    

    结果:

    降龙十八掌!
    磊落豪雄 
    弄清楚:我是谁? 
    

    源码下载

    源码仓库链接

    相关文章

      网友评论

        本文标题:萧峰与郭靖教你学会PHP的Trait

        本文链接:https://www.haomeiwen.com/subject/fbdpkxtx.html