PHP官方手册里面写的内容是

自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

<?php
trait Trait_a {
function getReturnType() { /**/ }
function getReturnDescription() { /**/ }
} trait Trait_b {
function getReturnType() { /**/ }
function getReturnDescription() { /**/ }
} class class1 extends parent_class1 {
use Trait_a;
/* ... */
} class class2 extends parent_class2 {
use Trait_a,Trait_b;
/* ... */
}

使用use语句利用这个特性。通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。

从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。

也就是 当前类 > trait > 父类

如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

以上方式仅允许排除掉其它方法,as 操作符可以 为某个方法引入别名。 注意,as 操作符不会对方法进行重命名,也不会影响其方法。

冲突的解决

在本例中 Talker 使用了 trait A 和 B。由于 A 和 B 有冲突的方法,其定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk。

Aliased_Talker 使用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名。

<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
} trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
} class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
} class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>

Note:

在 PHP 7.0 之前,在类里定义和 trait 同名的属性,哪怕是完全兼容的也会抛出 E_STRICT(完全兼容的意思:具有相同的访问可见性、初始默认值)。

修改方法的访问控制

使用 as 语法还可以用来调整方法的访问控制。

修改方法的访问控制

<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
} // 修改 sayHello 的访问控制
class MyClass1 {
use HelloWorld { sayHello as protected; }
} // 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}
?>
 

从 trait 来组成 trait

正如 class 能够使用 trait 一样,其它 trait 也能够使用 trait。在 trait 定义时通过使用一个或多个 trait,能够组合其它 trait 中的部分或全部成员。

从 trait 来组成 trait

<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
} trait World {
public function sayWorld() {
echo 'World!';
}
} trait HelloWorld {
use Hello, World;
} class MyHelloWorld {
use HelloWorld;
} $o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

以上例程会输出:

Hello World!

Trait 的抽象成员

为了对使用的类施加强制要求,trait 支持抽象方法的使用。

表示通过抽象方法来进行强制要求

<?php
trait Hello {
public function sayHelloWorld() {
echo 'Hello'.$this->getWorld();
}
abstract public function getWorld();
} class MyHelloWorld {
private $world;
use Hello;
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}
?>

Trait 的静态成员

Traits 可以被静态成员静态方法定义。

Example 静态变量

<?php
trait Counter {
public function inc() {
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
} class C1 {
use Counter;
} class C2 {
use Counter;
} $o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

Example  静态方法

<?php
trait StaticExample {
public static function doSomething() {
return 'Doing something';
}
} class Example {
use StaticExample;
} Example::doSomething();
?>

Trait 同样可以定义属性。

Example  定义属性

<?php
trait PropertiesTrait {
public $x = 1;
} class PropertiesExample {
use PropertiesTrait;
} $example = new PropertiesExample;
$example->x;
?>

Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。 在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。

Example  解决冲突

<?php
trait PropertiesTrait {
public $same = true;
public $different = false;
} class PropertiesExample {
use PropertiesTrait;
public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
public $different = true; // 致命错误
}
?>

Trait 是什么东西的更多相关文章

  1. PHP 面试知识点整理归纳

    基础篇了解大部分数组处理函数 array_chunk — 将一个数组分割成多个    array_column — 返回数组中指定的一列    array_combine — 创建一个数组,用一个数组 ...

  2. 对于PHP面试知识点的小结

    基础篇 了解大部分数组处理函数 字符串处理函数(区别 mb_ 系列函数) & 引用,结合案例分析 == 与 === 区别 isset 与 empty 区别 全部魔术函数理解 static.$t ...

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

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

  4. Scala Trait

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

  5. Scala学习笔记--特质trait

    http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...

  6. Scala入门系列(八):面向对象之trait

    基础知识 1 将trait作为接口使用 此时Trait就与Java中的接口非常类似,不过注意,在Scala中无论继承还是trait,统一都是extends关键字. Scala跟Java 8前一样不支持 ...

  7. Scala编程入门---面向对象编程之Trait

    Scala中Trait是一种特殊概念 首先我们可以将Triat做为接口来使用,此时的Triat就与java中的接口非常相似 在Triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出具体的 ...

  8. Spark基础-scala学习(三、Trait)

    面向对象编程之Trait trait基础知识 将trait作为接口使用 在trait中定义具体方法 在trait中定义具体字段 在trait中定义抽象字段 trait高级知识 为实例对象混入trait ...

  9. Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、

    1:Scala之函数式编程学习笔记: :Scala函数式编程学习: 1.1:Scala定义一个简单的类,包含field以及方法,创建类的对象,并且调用其方法: class User { private ...

随机推荐

  1. flex布局中flex-shrink的计算规则

    下面代码来自MDN html部分: <p>the width of content is 500px, flex-basic of flex item is 120px.</p> ...

  2. 创建ROS工程結構

    图像化显示目录工程结构:tree $ sudo apt install tree 1.创建ROS工作空间 $ mkdir -p catkin_ws/src # Create mutil-level d ...

  3. java 输出流 outputstream

    一:输入和输出概念 输入流(inputstream):对于java程序来说,从程序写入文件叫做输出. 输出流(outputstream):对于java程序来说,从文件读取数据,到java程序叫做输入. ...

  4. java集合(类似python的列表)

    一:学习方法 我们在学习一个类的时候,如果他是期其他类的实现类,我们在学习的时候,先学习他的共同的继承类,学习他们共有的方法,在学习他实现类的特殊方法.由共性--->特殊. 二:集合 1.集合和 ...

  5. PAT乙级1014

    1014 福尔摩斯的约会 (20 分)   大侦探福尔摩斯接到一张奇怪的字条:我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d& ...

  6. HDU 1171 (01背包问题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1171 分析: 例如数据 3 10    2 20    1 30    1 获得这样一个降序的数组: ...

  7. N项阶乘累加求和新算法

    pdf原版链接

  8. dataTable配置项说明

    Datatables是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 官网地址:https://datatables.net/ 中文说明地址:http:/ ...

  9. c语言指针篇

    不保证绝对正确,学习中所记录的一些笔记罢了,可能随着经历的增多,逐渐的完善, 不要完全相信我所记录的内容,可能因为编译协议版本的不同出现不同的结果. 也可能我写的根本就是错的,请相信自己动手得出来的结 ...

  10. springboot快速入门(一)——HelloWorld搭建

    一.起步 1.先导 凡技术必登其官网的原则,官网走一波:https://projects.spring.io/spring-boot/#quick-start 极力推荐一个springboot教程:h ...