官方说明:
PHP 实现了一种代码复用的方法,称为 trait。
首先我们了解trait语法之前,我们先看看的php的继承 。据我们了解,php继承是单继承,不是多继承的,就是一个类只能继承一个父级类,无法继承多类。为了实现多继承,trait就应运而生了 。
当然实现多继承,不止有trait一种方法你也可以使用接口(interface),我们今天只说trait语法,
官方文档: 地址
优先级
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
trait 方法又覆盖了基类中的实例
class Base {
public function sayHello() {
echo 'Hello BASE ';
}
}
trait SayWorld {
public function sayHello() {
// parent::sayHello();
echo 'SayWorld!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
// 输出内容 SayWorld ; 输出了trait 的方法属性
当前类的成员覆盖了 trait 的方法实例
class Base {
public function sayHello() {
echo 'Hello BASE ';
}
}
trait SayWorld {
public function sayHello() {
// parent::sayHello();
echo 'SayWorld!';
}
}
// 这样相当于本类继承了两个类
class MyHelloWorld extends Base {
use SayWorld;
public function sayHello()
{
echo 'MyHelloWorld!';
}
}
$o = new MyHelloWorld();
$o->sayHello();
// 输出内容 MyHelloWorld; 输出了本类的方法属性
多继承的实现实例:
class Base {
public function sayHello() {
echo 'Hello BASE ';
}
public function doThing() {
echo 'doingvBASE ';
}
}
trait SayWorld {
public function sayHello() {
// parent::sayHello();
echo 'SayWorld!';
}
public function sayBey() {
// parent::sayHello();
echo 'SayWorld!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
public function sayHello()
{
echo 'MyHelloWorld!';
}
}
$o = new MyHelloWorld();
$o->sayHello();
echo "<br/>" ;
$o->doThing();
echo "<br/>" ;
$o->sayBey();
echo "<br/>" ;
// MyHelloWorld!
// doingvBASE
// SayWorld!
我即可以使用trait 的方法 也可以使用父类的方法 ; 相当于我同时继承了两个类 ; 这是就是多继承的简单实现
多个 trait
通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
trait Cat {
public function catEat() {
// parent::sayHello();
echo '吃鱼!';
}
public function catHobby() {
// parent::sayHello();
echo '爱捉老鼠!';
}
}
trait Dog {
public function dogEat() {
echo '吃骨头!';
}
public function hobby() {
// parent::sayHello();
echo '看家护院!';
}
}
class Pets {
use Cat,Dog;
public function info()
{
echo 'Pets!';
}
}
$o = new Pets();
$o->info();
echo "<br/>" ; // Pets!
$o->catEat(); // 吃鱼!
echo "<br/>" ;
$o->dogEat(); // 吃骨头!
echo "<br/>" ;
// Pets!
// 吃鱼!
// 吃骨头!
冲突的解决
如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。
以上方式仅允许排除掉其它方法,as 操作符可以 为某个方法引入别名。 注意,as 操作符不会对方法进行重命名,也不会影响其方法
实例:
trait Cat {
public function eat() {
// parent::sayHello();
echo '吃鱼!';
}
public function hobby() {
// parent::sayHello();
echo '爱捉老鼠!';
}
}
trait Dog {
public function eat() {
echo '吃骨头!';
}
public function hobby() {
// parent::sayHello();
echo '看家护院!';
}
}
class Pets {
use Cat,Dog{
Cat::eat insteadof Dog; // cat .eat 替代 DOG.eat
Dog::hobby insteadof Cat; // hobby 继承 DOG
}
/*
use Cat,Dog{
Cat::eat as cEat; // 将 重名的方法 设置不重名
Dog::hobby as cHobby;
}
*/
public function info()
{
echo 'Pets!';
}
}
$o = new Pets();
$o->info();
echo "<br/>" ;
$o->eat();
echo "<br/>" ;
$o->hobby();
echo "<br/>" ;
//Pets!
// 吃鱼!
// 看家护院!
注意:
Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。
示例 # 解决冲突
trait PropertiesTrait {
public $same = true;
public $different = false;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true;
public $different = true; // 致命错误
}
更多的详细语法详见官方文档 : 地址
评论 (1)