Введение в использование трейтов в PHP

PHP

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";