参考

引文

在php中,为实现代码复用,有了继承,但是一个类只能继承一个父类,不支持多继承,接口支持多实现,但是接口又不太一样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑,严格意义上来说,不算代码复用,从php5.4开始,php实现了另外一种代码复用的方法,就是下文即将要说的trait。

trait

trait是为扩展类似php单继承的一种代码复用机制,解除单继承语言的限制,使开发人员能够自由地在不同层次结构中组合复用method。trait本身不能实例化,它依托于class存在。传统继承是上下层面的关系,trait则为水平层面的组合。

优先级

对于相同方法名的方法而言,当前类的方法覆盖trait方法,trait中方法覆盖继承的父类方法

  1. class Base {
  2. public function sayHello() {
  3. echo 'Hello ';
  4. }
  5. }
  6.  
  7. trait SayWorld {
  8. public function sayHello() {
  9. parent::sayHello();
  10. echo 'World!';
  11. }
  12.  
  13. public function sayPeter() {
  14. echo "\nhello trait peter\n";
  15. }
  16. }
  17.  
  18. class MyHelloWorld extends Base {
  19. use SayWorld;
  20. public function sayPeter() {
  21. echo "\nhello class peter\n";
  22. }
  23. }
  24.  
  25. $o = new MyHelloWorld();
  26. $o->sayHello();
  27. $o->sayPeter();

输出

 多个trait

在类中,可以声明多个trait,将多个trait组合到一个类中

  1. trait Hello {
  2. public function sayHello() {
  3. echo 'Hello ';
  4. }
  5. }
  6.  
  7. trait World {
  8. public function sayWorld() {
  9. echo 'World';
  10. }
  11. }
  12.  
  13. class MyHelloWorld {
  14. use Hello, World;
  15. public function sayExclamationMark() {
  16. echo '!';
  17. }
  18. }
  19.  
  20. $o = new MyHelloWorld();
  21. $o->sayHello();
  22. $o->sayWorld();
  23. $o->sayExclamationMark();

输出

trait冲突

如果trait之间定义了同名的方法,类中又组合了有同名方法的trait,会出现命名冲突,这个时候可以使用insteadof指明调用冲突方法中的某一个。trait中可以用as操作符为某个方法引入别名,注意引入别名并不会对原方法重命名,别名不能和已包含的trait中方法名重复

  1. trait A {
  2. public function smallTalk() {
  3. echo 'a';
  4. }
  5. public function bigTalk() {
  6. echo 'A';
  7. }
  8. public function helloPeter() {
  9. echo "hello peter\n";
  10. }
  11. }
  12.  
  13. trait B {
  14. public function smallTalk() {
  15. echo 'b';
  16. }
  17. public function bigTalk() {
  18. echo 'B';
  19. }
  20. public function helloAlice() {
  21. echo "hello alice\n";
  22. }
  23. }
  24.  
  25. class Talker {
  26. use A, B {
  27. B::smallTalk insteadof A;
  28. A::bigTalk insteadof B;
  29. }
  30. }
  31.  
  32. class TalkerAs {
  33. use A, B {
  34. B::smallTalk insteadof A;
  35. A::bigTalk insteadof B;
  36. B::bigTalk as talk;
  37. }
  38. }
  39.  
  40. class TalkerHello {
  41. use A, B {
  42. B::smallTalk insteadof A;
  43. A::bigTalk insteadof B;
  44. // A::helloPeter as helloAlice; 别名不允许和已包含trait中方法重名
  45. }
  46. }
  47.  
  48. $talker = new Talker();
  49. $talker->smallTalk();
  50. $talker->bigTalk();
  51. echo "\n";
  52. $talkerAs = new TalkerAs();
  53. $talkerAs->smallTalk();
  54. $talkerAs->bigTalk();
  55. $talkerAs->talk();

输出

trait组合trait

正如class可以使用多个trait,trait也可以使用trait

  1. trait Hello {
  2. public function sayHello() {
  3. echo 'Hello ';
  4. }
  5. }
  6.  
  7. trait World {
  8. public function sayWorld() {
  9. echo 'World!';
  10. }
  11. }
  12.  
  13. trait HelloWorld {
  14. use Hello, World;
  15. }
  16.  
  17. class MyHelloWorld {
  18. use HelloWorld;
  19. }
  20.  
  21. $o = new MyHelloWorld();
  22. $o->sayHello();
  23. $o->sayWorld();

输出

抽象成员方法

在trait中可以定义抽象方法,类中如果要使用trait,必须要实现trait中的抽象方法

  1. trait Hello {
  2. public function sayHelloWorld() {
  3. echo 'Hello ' . $this->getWorld() . "\n";
  4. }
  5. abstract public function getWorld();
  6. }
  7.  
  8. class MyHelloWorld {
  9. private $world;
  10. use Hello;
  11. public function getWorld() {
  12. return $this->world;
  13. }
  14. public function setWorld($val) {
  15. $this->world = $val;
  16. }
  17. }
  18.  
  19. $o = new MyHelloWorld();
  20. $o->sayHelloWorld();
  21. $o->setWorld('world');
  22. $o->sayHelloWorld();

输出

 属性

trait中也可以定义属性,但要注意trait定了某个属性后,使用该trait的类中就不能定义同样名称的属性,否则会产生fatal error。(属性如果是兼容的(同样的访问控制符和默认值),就不会产生fatal error,但在php7之前,会有E_STRICT提醒)

  1. trait PropertiesTrait {
  2. public $same = true;
  3. public $different = false;
  4. }
  5.  
  6. class PropertiesExample {
  7. use PropertiesTrait;
  8. public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
  9. public $different = true; // 致命错误
  10. }

php5.6

php7.1

trait的更多相关文章

  1. php中trait(性状)与generator(生成器)

    PHP中trait(性状)与generator(生成器) 一.trait (性状) 最近在看Josh Lockhat的<Modern PHP>,这本书很薄.但是其中给出了一个很重要的学习方 ...

  2. 【转】PHP的Trait 特性

    Trait是在PHP5.4中加入的,它既不是接口也不是类.主要是为了解决单继承语言的限制.是PHP多重继承的一种解决方案.例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情 ...

  3. Beginning Scala study note(7) Trait

    A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...

  4. 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait

    [源码下载] 速战速决 (4) - PHP: 类基础, 抽象类, 接口, trait 作者:webabcd 介绍速战速决 之 PHP 类基础 抽象类 接口 trait 示例1.类的相关知识点 1(基础 ...

  5. Scala的trait

    一:说明 1.介绍 2.功能 二:具体解释功能 1.定义接口 2.定义方法 3.定义字段 4.定义抽象字段 5.混合trait

  6. 利用GCTA工具计算复杂性状/特征(Complex Trait)的遗传相关性(genetic correlation)

    如文章"Genome-wide Complex Trait Analysis(GCTA)-全基因组复杂性状分析"中介绍的GCTA,是一款基于全基因组关联分析发展的分析工具,除了计算 ...

  7. PHP中Trait特性

    Trait是自 PHP 5.4.0 起添加的一个新特性,是 PHP 多重继承的一种解决方案.例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情,Trait 就是为了解决这个 ...

  8. scala 学习笔记(05) OOP(中)灵活的trait

    trait -- 不仅仅只是接口! 接上回继续,scala是一个非常有想法的语言,从接口的设计上就可以发现它的与众不同.scala中与java的接口最接近的概念是trait,见下面的代码: packa ...

  9. Scala Trait

    Scala Trait 大多数的时候,Scala中的trait有点类似于Java中的interface.正如同java中的class可以implement多个interface,scala中的cals ...

  10. scala中的trait

    这里的trait字面意思是特质或者特征,这个词翻译成特征比较合适.它的意义和java,c#中接口很类似.但是trait支持部分实现,也就是说可以在scala的trait中可以实现部分方法. 下面我们以 ...

随机推荐

  1. GO开发[一]:golang开发初探

    一.Golang的安装 1.https://dl.gocn.io/ (国内下载地址) 2.https://golang.org/dl/ (国外下载地址) 3.现在studygolang中文网也可以了h ...

  2. [转]scp用法

    从本地复制到远程 复制目录命令格式: scp -r local_folder remote_username@remote_ip:remote_folder 或者 scp -r local_folde ...

  3. npm 简单实用命令

    npm -v    查看版本号 npm get global             返回false表示默认本地安装 true全局安装 npm set global=true     设置默认为全局安 ...

  4. Mac从零配置Vim

    // 这是一篇导入进来的旧博客,可能有时效性问题. 1. 安装Homebrew (包管理器,用来安装Vim)& /usr/bin/ruby -e "$(curl -fsSL http ...

  5. JAXB应用实例

    过往的项目中数据存储都离不开数据库,不过最近做的一个项目的某些数据(比如人员信息.菜单.权限等等)却完全没有涉及任何数据库操作,直接XML搞定.这里无意比较优劣,因为数据库存储和XML存储本就有不同的 ...

  6. Java学习笔记【持续更新】

    一个简单的java程序如下: class Sakura { public static void main(String[] arges) { system.out.println("Hel ...

  7. 【Java学习笔记之十四】Java中this用法小节

    用类名定义一个变量的时候,定义的只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法. 那们类里面是够也应该有一个引用来访问自己的属性和方法纳? 呵呵,JAVA提供了一个很好的东西,就是 t ...

  8. BZOJ 1029: [JSOI2007]建筑抢修【优先队列+贪心策略】

    1029: [JSOI2007]建筑抢修 Time Limit: 4 Sec  Memory Limit: 162 MBSubmit: 4810  Solved: 2160[Submit][Statu ...

  9. MYSQL数据库增量备份

    MySQL数据库增量备份,在这之前修改我们的数据库配置文件/etc/my.cnf开启bin-log日志功能即可.接下来是我参考了下网上的一些方法,自己写的,主要还是要能学到他的一些思路和方法. #fu ...

  10. Java应用开发中的字符集与字符编码

    事出有因 在向HttpURLConnection的输出流写入内容时,因没有设置charset,导致接收方对数据的验签不一致. URL url = new URL(requestUrl); //打开连接 ...