1.Trait声明
trait trait名 {
//trait体
}
trait
体中可以包含静态变量、静态属性、静态方法、类常量、实例属性、实例方法。
trait
体中还可以含有 abstract
抽象方法,一个具体类 use
使用这个 trait
时必须实现这个抽象方法。抽象方法支持可见性修饰符 public
、protected
、private
。
trait
不可以继承,也不可以实例化。
2.use使用trait
2.1类use使用trait
//同一个trait被多个类use使用
class 类名1 {
use trait名;
}
class 类名2 {
use trait名;
}
//同一个类use使用多个trait
class 类名 {
use trait名1, trait名2;
}
2.2trait use使用trait
正如类能够 use
使用 trait
一样,trait
也能够 use
使用其它 trait
中的部分或全部成员。
//同一个trait被多个trait use使用
trait trait名1 {
use trait名3;
}
trait trait名2 {
use trait名3;
}
//同一个trait use使用多个trait
trait trait名3 {
use trait名1, trait名2;
}
3.访问trait中的成员
trait
中的成员访问步骤:首先通过类 use
使用 trait
,然后按照正常的类的成员的调用方式调用,不可以通过 trait
自身直接调用。
4.名称冲突
4.1常量名称冲突
当类中的常量 与 trait
中的常量名称相同时,类中的常量必须与 trait
中的常量具有相同的 final
、可见性、初始化值,否则会抛出 fatal error。
trait ConstantsTrait {
public const FLAG_MUTABLE = 1;
final public const FLAG_IMMUTABLE = 5;
}
class ConstantsExample {
use ConstantsTrait;
public const FLAG_IMMUTABLE = 5; // Fatal error
4.2实例属性名称冲突
当类中的属性 与 trait
中的属性名称相同时,类中的属性必须与 trait
中的属性具有相同的 可见性、readonly、类型、初始化值,否则会抛出 fatal error。
trait PropertiesTrait {
public $same = true;
public $different1 = false;
public bool $different2;
public bool $different3;
}
class PropertiesExample {
use PropertiesTrait;
public $same = true;
public $different1 = true; // Fatal error
public string $different2; // Fatal error
readonly protected bool $different3; // Fatal error
}
4.3实例方法名称冲突
当子类中的方法、trait中的方法、父类中的方法名称相同时,则覆盖规则为:子类中的方法会覆盖 trait 中的方法,而 trait 中的方法则会覆盖父类中的方法。
//子类中的方法会覆盖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!
//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!
当同一个类 use
多个 trait
但多个 trait
有同名方法时,可使用 insteadof
运算符 或 as
运算符两种方式解决命名冲突。
注意: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()方法代替A中的smallTalk()方法
B::smallTalk insteadof A;
//A中的bigTalk()方法代替B中的bigTalk()方法
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
//为B中的bigTalk()方法添加talk别名
B::bigTalk as talk;
}
}
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
//更改可见性
class MyClass1 {
use HelloWorld { sayHello as protected; }
}
//添加别名和更改可见性
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/php/phplang/28895.html