PHP 实现了一种代码复用的方法,称为 trait
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。
Trait 是 PHP 多重继承的一种解决方案。例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情,Trait 就是为了解决这个问题。
它为传统继承增加了水平特性的组合。
例子1: 使用trait关键字定义trait
trait first_trait{
public function hello(){
return 'hello';
}
}
例子2: 在Class里使用trait,要使用use关键字,使用多个trait时用英文逗号隔开
trait first_trait{
public function hello(){
return 'hello';
}
} trait second_trait{
public function world(){
return 'world';
}
} class first_class{
use first_trait,second_trait;
}
$obj=new first_class();
echo $obj->hello();
echo $obj->world();
例子3: 优先级
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
例子:从基类继承的成员会被 trait 插入的成员所覆盖
class Base {
public function sayHello() {
echo 'Hello ';
}
} trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
} class MyHelloWorld extends Base {
use SayWorld;
} $o = new MyHelloWorld();
$o->sayHello();
//输出的结果
Hello World!
例子:当前类的成员覆盖了 trait 的方法
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
} class TheWorldIsNotEnough {
use HelloWorld;
public function sayHello() {
echo 'Hello Universe!';
}
} $o = new TheWorldIsNotEnough();
$o->sayHello();
//输出的结果
Hello Universe!
例子4: trait之间的嵌套
trait first_trait{
public function hello(){
echo 'hello';
}
} trait second_trait{
//trait之间的嵌套
use first_trait;
public function world(){
echo 'world';
}
} class first_class{
use second_trait;
}
$obj=new first_class();
echo $obj->hello();
echo $obj->world();
例子5: 可以在trait中声明抽象方法,使用它的Class或trait必须实现抽象方法
trait first_trait{
public function hello(){
echo 'hello';
}
//抽象方法
public abstract function test();
} trait second_trait{
//trait之间的嵌套
use first_trait;
public function world(){
echo 'world';
} //实现first_trait 中的test方法
public function test(){
echo '!';
}
} class first_class{
use second_trait;
}
$obj=new first_class();
echo $obj->hello();
echo $obj->world();
echo $obj->test();
//会输出
helloworld!
例子6: 冲突的解决
如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。
以上方式仅允许排除掉其它方法,as 操作符可以将其中一个冲突的方法以另一个名称来引入,相当于方法的别名。
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; //trait B 的smallTalk方法会代替 trait A 的smallTalk方法
A::bigTalk insteadof B; //trait A 的bigTalk方法会代替 trait B 的bigTalk方法
}
} class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;//trait B 的smallTalk方法会代替 trait A 的smallTalk方法
A::bigTalk insteadof B;//trait A 的bigTalk方法会代替 trait B 的bigTalk方法
B::bigTalk as talk; //使用 as 操作符来定义了 talk方法 来作为 B 的 bigTalk方法 的别名
}
} $obj=new Talker();
$obj->smallTalk();
$obj->bigTalk();
//结果会输出 bA
$obj2=new Aliased_Talker();
$obj2->talk();//会输出B
例子7: 修改方法的访问控制
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; }
}
例子8: Trait 同样可以定义属性
trait PropertiesTrait {
public $x = 1;
} class PropertiesExample {
use PropertiesTrait;
} $example = new PropertiesExample;
$example->x;
如果 trait 定义了一个属性,那类将不能定义同样名称的属性,否则会产生一个错误。如果该属性在类中的定义与在 trait 中的定义兼容(同样的可见性和初始值)则错误的级别是 E_STRICT
,否则是一个致命错误。
trait PropertiesTrait {
public $same = true;
public $different = false;
} class PropertiesExample {
use PropertiesTrait;
public $same = true; // Strict Standards
public $different = true; // 致命错误
}
如果您阅读过此文章有所收获,请为我顶一个,如果文章中有错误的地方,欢迎指出。
相互学习,共同进步!
PHP 实现了一种代码复用的方法,称为 trait的更多相关文章
- PHP代码的多继承 -》 PHP代码复用新的姿势 trait
本文参考: http://php.net/language.oop5.traits 一.什么是trait 从PHP 5.4.0 开始 PHP 实现了一种新的代码复用方式 trait. 二.trait ...
- Atitit 代码复用的理解attilax总结
Atitit 代码复用的理解attilax总结 1.1. 继承1 1.1.1. 模式1:原型继承1 1.1.2. 模式2:复制所有属性进行继承 拷贝继承1 1.1.3. 模式3:混合(mix-in)1 ...
- php 代码复用机制
https://juejin.im/entry/5927ec4544d904006413f61d 提到 php 的代码复用,我们可能第一时间会想到继承,但是这种单继承语言一旦派生的子类过多,那么会产生 ...
- 深入理解JavaScript系列(46):代码复用模式(推荐篇)
介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { fun ...
- if __name__== "__main__" 的意思(作用)python代码复用
if __name__== "__main__" 的意思(作用)python代码复用 转自:大步's Blog http://www.dabu.info/if-__-name__ ...
- javascript 模式(1)——代码复用
程序的开发离不开代码的复用,通过代码复用可以减少开发和维护成本,在谈及代码复用的时候,会首先想到继承性,但继承并不是解决代码复用的唯一方式,还有其他的复用模式比如对象组合.本节将会讲解多种继承模式以实 ...
- 《JavaScript模式》第6章 代码复用模式
@by Ruth92(转载请注明出处) 第6章:代码复用模式 GoF 在其著作中提出的有关创建对象的建议原则: -- 优先使用对象组合,而不是类继承. 传统模式:使用类继承: 现代模式:"类 ...
- javascript代码复用(四)-混入、借用方法和绑定
这篇继续说js的现代复用模式:混入.借用方法和绑定. 混入 可以针对前面提到的通过属性复制实现代码复用的想法进行一个扩展,就是混入(mix-in).混入并不是复制一个完整的对象,而是从多个对象中复制出 ...
- javascript代码复用模式(二)
前面说到,javascript的代码复用模式,可分为类式继承和非类式继承(现代继承).这篇就继续类式继承. 类式继承模式-借用构造函数 使用借用构造函数的方法,可以从子构造函数得到父构造函数传任意数量 ...
随机推荐
- 灰色3D按钮组合
在线演示 本地下载
- java基础之final/static/static final
一.final 1.final修饰变量(常量) final修饰的成员变量表示常量,一旦给定初值既无法改变 2.final方法 final修饰方法,表示该方法不能被子类重写 好处:比非final方法要快 ...
- Ubuntu 12.04下安装OpenCV 2.4.2
http://sourceforge.net/projects/opencvlibrary/files/ Ubuntu 12.04下安装OpenCV 2.4.2 http://blog.csdn.ne ...
- [Android]开源中国源码分析之一---启动界面
开源中国android端版本号:2.4 启动界面: 在AndroidManifest.xml中找到程序的入口, <activity android:name=".AppStart&qu ...
- idea创建git分支
此时只是在本地创建好了分支,修改源代码后add,commit将本地分支提交到远程仓库 分支已创建,其它成员此时就可以从git拉分支
- maven 安装、运行、获取帮助 —— maven权威指南学习笔记(二)
这部分在网上很容易找到详细教程,这里就略写了. 基础:系统有配置好的jdk,通过 命令行 java -version,有类似下面的提示,表示java环境以配好 下载maven:官网 http://ma ...
- 转:gdb相关学习
声明本文转自:http://www.cnblogs.com/rosesmall/archive/2012/04/12/2444431.html (查看内存部分有补充) 另推荐一个入门级的好文章:htt ...
- 语音02_Delphi
网址 :http://www.exceletel.com/support/whtpapers/speech/delphi.htm Installing the Microsoft SAPI speec ...
- 刻录DVD.Win7系统盘(U盘)
ZC:Win7x86的U盘安装盘做好之后,U盘 里面会留有 引导信息,在以后不想要它(引导信息)的时候 该如果将它删掉?直接普通的格式化 能行吗? ZC:(20180423)发现,UltraISO制作 ...
- jquery 之 Deferred 使用
Deferred是jquery的promise接口的实现.他是非同步操作的通用接口,可以看作是完成一个任务之后再执行另外一个任务. 观察者模式是开发中经常使用的模式,这个模式由两个主要部分组成:主题和 ...