PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法。php的Traits和Go语言的组合功能有点类似,

通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。具体用法请看下面的代码:

<?php
trait Drive {public $carName = 'BMW';public function driving() {echo "driving {$this->carName}\n";}
}
class Person {public function age() {echo "i am 18 years old\n";}
}
class Student extends Person {use Drive;public function study() {echo "Learn to drive \n";}
}
$student = new Student();
$student->study();
$student->age();
$student->driving();

Learn to drive
i am 18 years old
driving BMW

上面的例子中,Student类通过继承Person,有了age方法,通过组合Drive,有了driving方法和属性carName。

如果Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢?通过下面的代码测试一下:

<?php
trait Drive {public function hello() {echo "hello 周伯通\n";}public function driving() {echo "周伯通不会开车\n";}
}
class Person {public function hello() {echo "hello 大家好\n";}public function driving() {echo "大家都会开车\n";}
}
class Student extends Person {use Drive;//trait 的方法覆盖了基类Person中的方法,所以Person中的hello 和driving被覆盖public function hello() {echo "hello 新学员\n";//当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,所以此处hello会覆盖trait中的hello
    }
}
$student = new Student();
$student->hello();
$student->driving();

hello 新学员
周伯通不会开车

因此得出结论:当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法。

如果要组合多个Trait,通过逗号分隔 Trait名称:

use Trait1, Trait2;

如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误。

<?php
trait Trait1 {public function hello() {echo "Trait1::hello\n";}public function hi() {echo "Trait1::hi\n";}
}
trait Trait2 {public function hello() {echo "Trait2::hello\n";}public function hi() {echo "Trait2::hi\n";}
}
class Class1 {use Trait1, Trait2;
}//输出:Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in

使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码:

<?php
trait Trait1 {public function hello() {echo "Trait1::hello \n";}public function hi() {echo "Trait1::hi \n";}
}
trait Trait2 {public function hello() {echo "Trait2::hello\n";}public function hi() {echo "Trait2::hi\n";}
}
class Class1 {use Trait1, Trait2 {Trait2::hello insteadof Trait1;Trait1::hi insteadof Trait2;}
}
class Class2 {use Trait1, Trait2 {Trait2::hello insteadof Trait1;Trait1::hi insteadof Trait2;Trait2::hi as hei;Trait1::hello as hehe;}
}
$Obj1 = new Class1();
$Obj1->hello();
$Obj1->hi();
echo "\n";
$Obj2 = new Class2();
$Obj2->hello();
$Obj2->hi();
$Obj2->hei();
$Obj2->hehe();

Trait2::hello
Trait1::hi Trait2::hello
Trait1::hi
Trait2::hi
Trait1::hello 

as关键词还有另外一个用途,那就是修改方法的访问控制:

<?php
trait Hello {public function hello() {echo "hello,我是周伯通\n";}
}
class Class1 {use Hello {hello as protected;}
}
class Class2 {use Hello {Hello::hello as private hi;}
}
$Obj1 = new Class1();
$Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的
$Obj2 = new Class2();
$Obj2->hello(); # 输出: hello,我是周伯通,因为原来的hello方法仍然是公共的
$Obj2->hi();  # 报致命错误,因为别名hi方法被修改成私有的

Uncaught Error: Call to protected method Class1::hello() from context '' in D:\web\mytest\p.php:18

Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:

<?php
trait Hello {public function sayHello() {echo "Hello 我是周伯通\n";}
}
trait World {use Hello;public function sayWorld() {echo "hello world\n";}abstract public function getWorld();public function inc() {static $c = 0;$c = $c + 1;echo "$c\n";}public static function doSomething() {echo "Doing something\n";}
}
class HelloWorld {use World;public function getWorld() {return 'do you get World ?';}
}
$Obj = new HelloWorld();
$Obj->sayHello();
$Obj->sayWorld();
echo $Obj->getWorld() . "\n";
HelloWorld::doSomething();
$Obj->inc();
$Obj->inc();

Hello 我是周伯通
hello world
do you get World ?
Doing something
1
2

PHP中的Traits用法详解相关推荐

  1. C++中substr()函数用法详解

    C++中substr()函数用法详解 原型: string substr (size_t pos = 0, size_t len = npos) const; 返回一个新构造的string对象,其值初 ...

  2. c++中vector的用法详解

    c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间 ...

  3. C#中NameValueCollection类用法详解

    C#中NameValueCollection类用法详解,1.NameValueCollection类集合是基于 NameObjectCollectionBase 类. 但与 NameObjectCol ...

  4. c++ memset 语言_C++中memset函数用法详解

    本文实例讲述了C++中memset函数用法.分享给大家供大家参考,具体如下: 功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,块的大小由第三个参数指定,这个函数通常 ...

  5. python中的super用法详解_【Python】【类】super用法详解

    一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: class A: def __init__(sel ...

  6. JSP 中EL表达式用法详解

    EL 全名为Expression Language EL 语法很简单,它最大的特点就是使用上很方便.接下来介绍EL主要的语法结构: ${sessionScope.user.sex} 所有EL都是以${ ...

  7. java中throws用法_java中throws实例用法详解

    在程序出现异常时,会有一个抛出异常的throw出现,这里我们要跟今天所讲的throws区分开.throws的作用是声明抛出,在名称上也跟throw有所不同.下面我们就throws对策概念.语法.实例带 ...

  8. python中的super用法详解_Python中super函数用法实例分析

    本文实例讲述了python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简 ...

  9. STL 中map的用法详解

    STL 中map的用法详解 Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可 ...

最新文章

  1. macos 全局快捷键 打开 iterm_MouseInc – 完全免费的全局鼠标手势增强工具 | 马小帮...
  2. Tableau可视化分析实战系列Tableau基础概念全解析 (一)-数据结构及字段
  3. 你多久更新一次简历,决定了你的收入多久能提升
  4. 教学思路SQL之预备课程学习 建库、建表、建约束、关系、部分T-sql语句
  5. -Dmaven.multiModuleProjectDirectory system propery
  6. 疯狂html5+css3+javascript讲义 pdf_成为一名优秀的HTML5前端工程师需要掌握哪些技能?...
  7. 活动目录应用篇一:使用windows server 2008 backup备份AD是的账户权限问题
  8. 代理模式、动态代理及其应用
  9. python常用内置方法_Python3 常用的几个内置方法
  10. 计算1到100的整数和
  11. spring cloud超时时间设置
  12. python知识:json格式文本;异常处理;字符串处理;unicode类型和str类型转换
  13. 安装torchvision时,报错error: command ‘aarch64-linux-gnu-gcc‘ failed with exit status 1
  14. php如何用菜刀连接getshell,xise菜刀后门箱子制作:Sqlmao连接Mysql实现Getshell
  15. [Angular] - 01 Architecture and workflow
  16. 领英开发客户的思路和方法!拥有超过2万6千个领英好友后,你也能坐等流量和询盘。
  17. 自组网(Adhoc)和基础网(Infra)
  18. SCADA系统架构、类型和应用
  19. 数学建模选修课笔记——模糊聚类分析
  20. Android Sensor感应器介绍(三)获取用户移动方向,指南针原理

热门文章

  1. Nginx配置同一个域名同时支持http与https两种方式访问
  2. 展开字符串(dfs)
  3. total commander按文件夹大小显示
  4. 和菜鸟一起学android4.0.3源码之lcd屏幕背光调节
  5. 条码扫描二维码扫描——ZXing android 源码简化
  6. debugfs查看文件块号,dd命令读指定块号的内容
  7. Linux之fgrep命令
  8. 在线黑客帝国文字效果生成工具
  9. 关于eclipse新建web项目,提示:The superclass javax.servlet.http.HttpServlet was not found on the Java解决办法...
  10. 一道简单的多维数组取值问题