当前位置:首页 > 日记 > 正文

PHP中Trait及其应用详解

PHP中Trait及其应用详解

从PHP的5.4.0版本开始,PHP提供了一种全新的代码复用的概念,那就是Trait。Trait其字面意思是”特性”、”特点”,我们可以理解为,使用Trait关键字,可以为PHP中的类添加新的特性。 

熟悉面向对象的都知道,软件开发中常用的代码复用有继承和多态两种方式。在PHP中,只能实现单继承。而Trait则避免了这点。下面通过简单的额例子来进行对比说明。 

1. 继承 VS 多态 VS Trait 

现在有Publish.php和Answer.php这两个类。要在其中添加LOG功能,记录类内部的动作。有以下几种方案:

 继承
 多态
 Trait 

1.1. 继承 

如图:

代码结构如下:

// Log.php<?phpClass Log{ public function startLog() {  // echo ... } public function endLog() {  // echo ... }} 
// Publish.php<?phpClass Publish extends Log{} // Answer.php<?phpClass Answer extends Log{} 

可以看到继承的确满足了要求。但这却违背了面向对象的原则。而发布(Publish)和回答(Answer)这样的操作和日志(Log)之间的关系并不是子类与父类的关系。所以不推荐这样使用。 

1.2. 多态 

如图:

 

实现代码:

 // Log.php<?phpInterface Log{ public function startLog(); public function endLog();}
// Publish.php<?phpClass Publish implements Log{ public function startLog() {  // TODO: Implement startLog() method. } public function endLog() {  // TODO: Implement endLog() method. }} 
// Answer.php<?phpClass Answer implements Log{ public function startLog() {  // TODO: Implement startLog() method. } public function endLog() {  // TODO: Implement endLog() method. }} 
记录日志的操作应该都是一样的,因此,发布(Publish)和回答(Answer)动作中的日志记录实现也是一样的。很明显,这违背了DRY(Don't Repeat Yourself)原则。所以是不推荐这样实现的。 

1.3. Trait 

如图:

 

实现代码如下:

 // Log.php<?phptrait Log{ public function startLog() {  // echo .. } public function endLog() {  // echo .. }} 
// Publish.php<?phpclass Publish { use Log;}$publish = new Publish();$publish->startLog();$publish->endLog(); 
// Answer.php<?phpclass Answer { use Log;}$answer = new Answer();$answer->startLog();$answer->endLog(); 

可以看到,我们在没有增加代码复杂的情况下,实现了代码的复用。 

1.4. 结论 

继承的方式虽然也能解决问题,但其思路违背了面向对象的原则,显得很粗暴;多态方式也可行,但不符合软件开发中的DRY原则,增加了维护成本。而Trait方式则避免了上述的不足之处,相对优雅的实现了代码的复用。 

2. Trait的作用域 

了解了Trait的好处,我们还需要了解其实现中的规则,先来说一下作用域。这个比较好证明,实现代码如下:

 <?phpclass Publish { use Log; public function doPublish() {  $this->publicF();  $this->protectF();  $this->privateF(); }}$publish = new Publish();$publish->doPublish(); 

执行上述代码输出结果如下:
public function
protected function
private function

可以发现,Trait的作用域在引用该Trait类的内部是都可见的。可以理解为use关键字将Trait的实现代码Copy了一份到引用该Trait的类中。 

3. Trait中属性的优先级

说到优先级,就必须要有一个对比的参照物,这里的参照对象时引用Trait的类及其父类。 

通过以下的代码来证明Trait应用中的属性的优先级:

 <?phptrait Log{ public function publicF() {  echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() {  echo __METHOD__ . ' protected function' . PHP_EOL; }}class Question{ public function publicF() {  echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() {  echo __METHOD__ . ' protected function' . PHP_EOL; }}class Publish extends Question{ use Log; public function publicF() {  echo __METHOD__ . ' public function' . PHP_EOL; } public function doPublish() {  $this->publicF();  $this->protectF(); }}$publish = new Publish();$publish->doPublish(); 

上述代码的输出结果如下:
Publish::publicF public function
Log::protectF protected function

通过上面的例子,可以总结出Trait应用中的优先级如下:
 1.来自当前类的成员覆盖了 trait 的方法
 2.trait 覆盖了被继承的方法 

类成员优先级为:当前类>Trait>父类

4. Insteadof和As关键字 

在一个类中,可以引用多个Trait,如下:

 <?phptrait Log{  public function startLog()  {    echo __METHOD__ . ' public function' . PHP_EOL;  }  protected function endLog()  {    echo __METHOD__ . ' protected function' . PHP_EOL;  }}trait Check{  public function parameterCheck($parameters) {    // do sth  }}class Publish extends Question{  use Log,Check;  public function doPublish($para) {    $this->startLog();    $this->parameterCheck($para);    $this->endLog();  }} 

通过上面的方式,我们可以在一个类中引用多个Trait。引用多个Trait的时候,就容易出问题了,最常见的问题就是两个Trait中如果出现了同名的属性或者方法该怎么办呢?这个时候就需要用到Insteadof 和 as 这两个关键字了.请看如下实现代码:

 <?phptrait Log{  public function parameterCheck($parameters)  {    echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL;  }  public function startLog()  {    echo __METHOD__ . ' public function' . PHP_EOL;  }}trait Check{  public function parameterCheck($parameters)  {    echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL;  }  public function startLog()  {    echo __METHOD__ . ' public function' . PHP_EOL;  }}class Publish{  use Check, Log {    Check::parameterCheck insteadof Log;    Log::startLog insteadof Check;    Check::startLog as csl;  }  public function doPublish()  {    $this->startLog();    $this->parameterCheck('params');    $this->csl();  }}$publish = new Publish();$publish->doPublish(); 

执行上述代码,输出结果如下:
 Log::startLog public function
Check::parameterCheck parameter checkparams
Check::startLog public function

就如字面意思一般,insteadof关键字用前者取代了后者,as 关键字给被取代的方法起了一个别名。 

在引用Trait时,使用了use关键字,use关键字也用来引用命名空间。两者的区别在于,引用Trait时是在class内部使用的。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

相关文章

PS怎么设计一款漂亮的教师节艺术字

PS怎么设计一款漂亮的教师节艺术字

教师节,漂亮,艺术字,电脑软件,PS,Photoshop是我们日常工作学习中,经常用到的一款图像处理软件,今天给大家分享一下,怎么用PS制作漂亮的艺术字效果。主要用到图片背景素材和透明的艺术字,还有一些发光星星作为点缀效果。软件名称:Adobe Photoshop…

excel2013计算百分比的方法excel20

excel2013计算百分比的方法excel20

计算,方法,百分比,电脑软件,strong,  在Excel中经常需要计算数据的值得百分比。而因为2013的界面有比较大的改动,很多朋友都不知道该如何入手。下面是小编整理的excel2013计算百分比的方法以供大家阅读。excel2013计算百分比的方法步骤1:假…

jQuery 添加样式属性的优先级别方

jQuery 添加样式属性的优先级别方

方法,样式属性,级别,推荐,电脑软件,jQuery类中添加多个属性$('#five .a').css({ color:'blue', border:'2px solid green', background:'blue'});jQuer为元素添加类$('#five .a').addClass('funny');HTML code<style>.funny…

AI图形怎么做布尔运算? ai布尔运算

AI图形怎么做布尔运算? ai布尔运算

布尔运算,图形,教程,怎么做,电脑软件,ai里的布尔运算怎么做?今天我们就来看看详细的教程,是基础教程,请继续关注。软件名称:Adobe Illustrator CS6 (AI cs6) 精简绿色中文版(32位+64位)软件大小:205MB更新时间:2014-05-111、打开ai,新建文件,选择&l…

怎么使用excel2013做数据透视表Exc

怎么使用excel2013做数据透视表Exc

数据,方法,步骤,透视,透视图,  Excel最新版更新到2013,相比2003、2007和2010,2013的excel界面方面有一定变化,在操作方面也有一定的便捷性。那么如何使用excel2013做一些简单的数据汇总、透视,以及在数据透视表中进行计算、展现等呢?那么下…

PS怎么绘制大头儿子的头像?

PS怎么绘制大头儿子的头像?

绘制,头像,大头,儿子,电脑软件,PS怎么绘制大头儿子的头像? 大头儿子是一个非常可爱的都画人物,该怎么绘制出来坑呢?下面我们就来看看详细的教程。软件名称:Adobe photoshop 7.01 官方正式简体中文版软件大小:154MB更新时间:2013-04-191、先用钢…

photoshop 水晶风格按钮

photoshop 水晶风格按钮

按钮,水晶,风格,电脑软件,photoshop,最终效果图 12 3 4 5 阅读全文 1 23 4 5 阅读全文 1 2 34 5 阅读全文 1 2 3 45 阅读全文 最终效果图 1 2 3 4 5阅读全文…

怎么在PowerPoint演示文稿中插入公

怎么在PowerPoint演示文稿中插入公

公式,演示文稿,电脑软件,PowerPoint,PPT,  公式编辑器用来输入统计函数、数学函数、微积分方程式等复杂方程式。通过单击&ldquo;插入&rdquo;菜单,选取&ldquo;对象&rdquo;命令,弹出&ldquo;插入对象&rdquo;对话框等步骤可以插入想要的公式。…

如何使用JS在HTML中自定义字符串格

如何使用JS在HTML中自定义字符串格

字符串格式化,自定义,如何使用,电脑软件,HTML,Python中支持字符串格式化,其基本形式如下:str = "I'm %s, %s years old." % ('jack', 19) print(str) #结果: I'm jack, 19 years old. 在JavaScript中虽没有类似的方法,但我们可以利用字…

ES6中的rest参数与扩展运算符详解

ES6中的rest参数与扩展运算符详解

运算符,参数,扩展,详解,电脑软件,前言本文主要给大家介绍了关于ES6中rest参数与扩展运算符的相关内容,rest参数和扩展运算符都是ES6新增的特性。rest参数的形式为:...变量名;扩展运算符是三个点(...)。下面话不多说了,来一起看看详细的介绍:rest参…

ps怎么使用画笔画翠绿的小草?

ps怎么使用画笔画翠绿的小草?

电脑软件,ps,如何用ps制作草?为什么PHOTOSHOP自定义的画笔在使用时会有透明度;下面我们就来看看。软件名称:Adobe Photoshop 8.0 中文完整绿色破解版软件大小:150.1MB更新时间:2015-11-041、打开图片素材,最好是叶子轮廓清晰的2、勾出选区,编辑&md…

word2010中如何对文字进行排序

word2010中如何对文字进行排序

文字,排序,步骤,电脑软件,strong,  word2010的排序功能异常强大,不光可以对数字排序,还可以对文字进行排序,那么下面就由小编给大家分享下word2010中对文字进行排序的技巧,希望能帮助到您,有需要的朋友可以来看看哦。word2010对文字排序的步骤…