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

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

结果:

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

源码下载

源码仓库链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C/C++基础

我所理解的C++反射机制

在实际的项目中,听到师兄说C++中用到了反射,出于好奇,就查阅相关资料,发现强大的C++本身并不支持反射,反而Java支持反射机制。当我得知这个事实时,一直唯C...

502
来自专栏开发技术

spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方

  此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研...

1423
来自专栏Hongten

Struts2 IncludeModules(包含 <include file="login.xml" />)

xml文件当成struts.xml包含在struts.xml中,比如我们看到的login.xml

421
来自专栏Java架构师历程

Spring MVC中使用Swagger生成API文档

实际项目中非常需要写文档,提高Java服务端和Web前端以及移动端的对接效率。 听说Swagger这个工具,还不错,就网上找了些资料,自己实践了下。 一:Sw...

1395
来自专栏代码散人

Vapor奇幻之旅(04Routing)

Vapor的Routing提供了RouteBuilder和RouteCollection

632
来自专栏微信公众号:Java团长

我的编码习惯 —— Controller规范

第一篇文章中,我贴了2段代码,第1段是原生态的,第2段是我指定了接口定义规范,使用AOP技术之后最终交付的代码,从15行到1行,自己感受一下。

1054
来自专栏Android先生

Dagger2神器入门(二)

在Dagger2神器入门(一)中,我们了解了什么是依赖注入,那么在这一章中,我们将逐渐入门Dagger2。接下来我们会通过demo形式给大家展现Dagger2的...

823
来自专栏技术之路

Caliburn.Micro学习笔记(四)----IHandle<T>实现多语言功能

说一下IHandle<T>实现多语言功能 因为Caliburn.Micro是基于MvvM的UI与codebehind分离, binding可以是双向的所以我们想...

1987
来自专栏菩提树下的杨过

利用Reflector把"闭包"看清楚

今天老赵在园子里发了一篇文章"警惕匿名方法造成的变量共享",立即引起了大家的广泛关注(老赵就是园子的"人气天王",呵呵),而且这个问题园子里也有其它几篇文章做了...

1875
来自专栏前端侠2.0

asp。net5的依赖注入 原

昨天读asp.net5的doc,看到了configure的配置时,提到在controller中访问配置就是通过依赖注入的。asp.net5的很多功能都通过依赖注...

531

扫码关注云+社区