PHP — это язык с единым наследованием.Чтобы позволить разработчикам повторно использовать методы в независимых классах в различных иерархиях, начиная с PHP 5.4.0, PHP реализовал метод повторного использования кода Trait, который не может быть создан сам по себе, способ достижения множественного наследования.
- Пример
trait A {
public function sayHello() {
echo "Hello\n";
}
}
class B {
public function sayWorld() {
echo "World\n";
}
}
class C extends B {
use A;
public function sayHi() {
echo "Hi\n";
}
}
$c = new C();
$c->sayHi();
$c->sayHello();
$c->sayWorld();
- Приоритетный производный класс>признак>базовый класс
trait A {
public function sayHello() {
echo "Hello trait\n";
}
public function sayHi() {
echo "Hi trait\n";
}
}
class B {
public function sayHello() {
echo "Hello class\n";
}
public function sayHi() {
echo "Hi class\n";
}
}
class C extends B {
use A;
public function sayHello() {
echo "Hello C\n";
}
}
$c = new C();
$c->sayHello();
$c->sayHi();
- Несколько признаков, разделенных запятыми.
trait Hello {
public function sayHello() {
echo "Hello ";
}
}
trait World {
public function sayWorld() {
echo "World";
}
}
class Test {
use Hello,World;
public function sayHelloWorld() {
echo "!\n";
}
}
$test = new Test();
$test->sayHello();
$test->sayWorld();
$test->sayHelloWorld();
- Решение конфликта
trait A {
public function sayHello() {
echo "Hello A\n";
}
public function sayHi() {
echo "Hi A\n";
}
}
trait B {
public function sayHello() {
echo "Hello B\n";
}
public function sayHi() {
echo "Hi B\n";
}
}
class C {
// 使用insteadof操作符明确指定使用冲突方法中的哪一个
use A,B {
A::sayHello insteadof B;
B::sayHi insteadof A;
}
}
class D {
use A,B {
A::sayHello insteadof B;
B::sayHi insteadof A;
A::sayHi as hi; // as操作符为某个方法引入别名,解决多个trait都插入一个同名方法的冲突
}
}
$c = new C();
$c->sayHello();
$c->sayHi();
echo "\n";
$d = new D();
$d->sayHello();
$d->sayHi();
$d->hi();
- Настройте контроль доступа для методов, использующих синтаксис as
trait Hello {
public function sayHello() {
echo "Hello trait\n";
}
}
class A {
use Hello {
Hello::sayHello as protected; // 使用as操作符修改sayHello的访问控制
}
}
class B {
use Hello {
Hello::sayHello as private sayHi; // 使用as操作符给sayHello引入一个别名并修改别名的访问控制,原版sayHello的访问控制不改变
}
}
$a = new A();
// PHP Fatal error: Uncaught Error: Call to protected method A::sayHello() from context '' in trait5.php:158
$a->sayHello();
$b = new B();
$b->sayHello();
// PHP Fatal error: Uncaught Error: Call to private method B::sayHi() from context '' in trait5.php:162
$b->sayHi();
- Объединение признаков с помощью признаков
trait Hello {
public function sayHello() {
echo "Hello ";
}
}
trait World {
public function sayWorld() {
echo "World!\n";
}
}
trait HelloWorld {
use Hello,World;
}
class Hi {
use HelloWorld;
}
$hi = new Hi();
$hi->sayHello();
$hi->sayWorld();
- Черты используют абстрактные методы для обеспечения соблюдения требований к классам, которые объединяют черты.
trait Hello {
public function sayHello() {
echo "Hello " . $this->getWorld();
}
// 抽象方法
abstract public function getWorld();
}
class Hi {
private $world;
use Hello; // 组合trait
// 实现抽象方法
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}
$hi = new Hi();
$hi->setWorld("world!\n");
$hi->sayHello();
- Черты определяют статические свойства и статические методы
trait Counter {
public function inc() {
// 静态属性
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
// 静态方法
public static function doSomething() {
return "Doing Something\n";
}
}
class Test {
use Counter;
}
$test = new Test();
$test->inc();
echo $test::doSomething();
$test->inc();
- свойство определения признака
trait A {
public $name = 'frankphper';
public $age = 18;
}
class B {
use A;
public $name = 'frankphper';
public $age = 28;
}
$b = new B();
echo $b->name; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
echo "\n";
echo $b->age; // PHP Fatal error: B and A define the same property ($age) in the composition of B. However, the definition differs and is considered incompatible. Class was composed in trait5.php on line 250
echo "\n";