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

图片描述

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

trait的使用场景

如如下应用场景:git

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 技能。app

用Trait就能解决此问题:spa

<?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();

结果以下:.net

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

方法/属性的重写

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

<?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 方法,得出的结果是:blog

降龙十八掌!

当方法或属性同名时,当前类中的方法会覆盖 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();

结果:

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

源码下载

源码仓库连接

相关文章
相关标签/搜索