PHP的多继承Trait特性

自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

Example #1 Trait 示例

  1. <?php
  2. trait ezcReflectionReturnInfo {
  3. function getReturnType() { /*1*/ }
  4. function getReturnDescription() { /*2*/ }
  5. }
  6. class ezcReflectionMethod extends ReflectionMethod {
  7. use ezcReflectionReturnInfo;
  8. /* ... */
  9. }
  10. class ezcReflectionFunction extends ReflectionFunction {
  11. use ezcReflectionReturnInfo;
  12. /* ... */
  13. }
  14. ?>

优先级

从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。

Example #2 优先顺序示例

从基类继承的成员被插入的 SayWorld Trait 中的 MyHelloWorld 方法所覆盖。其行为 MyHelloWorld 类中定义的方法一致。优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。

  1. <?php
  2. class Base {
  3. public function sayHello() {
  4. echo 'Hello ';
  5. }
  6. }
  7. trait SayWorld {
  8. public function sayHello() {
  9. parent::sayHello();
  10. echo 'World!';
  11. }
  12. }
  13. class MyHelloWorld extends Base {
  14. use SayWorld;
  15. }
  16. $o = new MyHelloWorld();
  17. $o->sayHello();
  18. ?>
  19. 以上例程会输出:
  20. Hello World!

Example #3 另一个优先级顺序的例子

  1. <?php
  2. trait HelloWorld {
  3. public function sayHello() {
  4. echo 'Hello World!';
  5. }
  6. }
  7. class TheWorldIsNotEnough {
  8. use HelloWorld;
  9. public function sayHello() {
  10. echo 'Hello Universe!';
  11. }
  12. }
  13. $o = new TheWorldIsNotEnough();
  14. $o->sayHello();
  15. ?>
  16. 以上例程会输出:
  17. Hello Universe!

多个 trait

通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。

Example #4 多个 trait 的用法

  1. <?php
  2. trait Hello {
  3. public function sayHello() {
  4. echo 'Hello ';
  5. }
  6. }
  7. trait World {
  8. public function sayWorld() {
  9. echo 'World';
  10. }
  11. }
  12. class MyHelloWorld {
  13. use Hello, World;
  14. public function sayExclamationMark() {
  15. echo '!';
  16. }
  17. }
  18. $o = new MyHelloWorld();
  19. $o->sayHello();
  20. $o->sayWorld();
  21. $o->sayExclamationMark();
  22. ?>
  23. 以上例程会输出:
  24. Hello World!

冲突的解决

如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。

以上方式仅允许排除掉其它方法,as 操作符可以 为某个方法引入别名。 注意,as 操作符不会对方法进行重命名,也不会影响其方法。

Example #5 冲突的解决

在本例中 Talker 使用了 trait A 和 B。由于 A 和 B 有冲突的方法,其定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk。

Aliased_Talker 使用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名。

  1. <?php
  2. trait A {
  3. public function smallTalk() {
  4. echo 'a';
  5. }
  6. public function bigTalk() {
  7. echo 'A';
  8. }
  9. }
  10. trait B {
  11. public function smallTalk() {
  12. echo 'b';
  13. }
  14. public function bigTalk() {
  15. echo 'B';
  16. }
  17. }
  18. class Talker {
  19. use A, B {
  20. B::smallTalk insteadof A;
  21. A::bigTalk insteadof B;
  22. }
  23. }
  24. class Aliased_Talker {
  25. use A, B {
  26. B::smallTalk insteadof A;
  27. A::bigTalk insteadof B;
  28. B::bigTalk as talk;
  29. }
  30. }
  31. ?>

Note: 在 PHP 7.0 之前,在类里定义和 trait 同名的属性,哪怕是完全兼容的也会抛出 E_STRICT(完全兼容的意思:具有相同的访问可见性、初始默认值)。

修改方法的访问控制

使用 as 语法还可以用来调整方法的访问控制。

Example #6 修改方法的访问控制

  1. <?php
  2. trait HelloWorld {
  3. public function sayHello() {
  4. echo 'Hello World!';
  5. }
  6. }
  7. // 修改 sayHello 的访问控制
  8. class MyClass1 {
  9. use HelloWorld { sayHello as protected; }
  10. }
  11. // 给方法一个改变了访问控制的别名
  12. // 原版 sayHello 的访问控制则没有发生变化
  13. class MyClass2 {
  14. use HelloWorld { sayHello as private myPrivateHello; }
  15. }
  16. ?>

从 trait 来组成 trait

正如 class 能够使用 trait 一样,其它 trait 也能够使用 trait。在 trait 定义时通过使用一个或多个 trait,能够组合其它 trait 中的部分或全部成员。

Example #7 从 trait 来组成 trait

  1. <?php
  2. trait Hello {
  3. public function sayHello() {
  4. echo 'Hello ';
  5. }
  6. }
  7. trait World {
  8. public function sayWorld() {
  9. echo 'World!';
  10. }
  11. }
  12. trait HelloWorld {
  13. use Hello, World;
  14. }
  15. class MyHelloWorld {
  16. use HelloWorld;
  17. }
  18. $o = new MyHelloWorld();
  19. $o->sayHello();
  20. $o->sayWorld();
  21. ?>
  22. 以上例程会输出:
  23. Hello World!

Trait 的抽象成员

为了对使用的类施加强制要求,trait 支持抽象方法的使用。

Example #8 表示通过抽象方法来进行强制要求

  1. <?php
  2. trait Hello {
  3. public function sayHelloWorld() {
  4. echo 'Hello'.$this->getWorld();
  5. }
  6. abstract public function getWorld();
  7. }
  8. class MyHelloWorld {
  9. private $world;
  10. use Hello;
  11. public function getWorld() {
  12. return $this->world;
  13. }
  14. public function setWorld($val) {
  15. $this->world = $val;
  16. }
  17. }
  18. ?>

Trait 的静态成员

Traits 可以被静态成员静态方法定义。

Example #9 静态变量

  1. <?php
  2. trait Counter {
  3. public function inc() {
  4. static $c = 0;
  5. $c = $c + 1;
  6. echo "$c\n";
  7. }
  8. }
  9. class C1 {
  10. use Counter;
  11. }
  12. class C2 {
  13. use Counter;
  14. }
  15. $o = new C1(); $o->inc(); // echo 1
  16. $p = new C2(); $p->inc(); // echo 1
  17. ?>

Example #10 静态方法

  1. <?php
  2. trait StaticExample {
  3. public static function doSomething() {
  4. return 'Doing something';
  5. }
  6. }
  7. class Example {
  8. use StaticExample;
  9. }
  10. Example::doSomething();
  11. ?>

Trait 同样可以定义属性。

Example #11 定义属性

  1. <?php
  2. trait PropertiesTrait {
  3. public $x = 1;
  4. }
  5. class PropertiesExample {
  6. use PropertiesTrait;
  7. }
  8. $example = new PropertiesExample;
  9. $example->x;
  10. ?>

Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。 在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。

Example #12 解决冲突

  1. <?php
  2. trait PropertiesTrait {
  3. public $same = true;
  4. public $different = false;
  5. }
  6. class PropertiesExample {
  7. use PropertiesTrait;
  8. public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
  9. public $different = true; // 致命错误
  10. }
  11. ?>

文章内容来自PHP官方手册 https://www.php.net/traits

点赞 ( 2 )

16 条评论

  1. cheap flights now

    Hey there! Do you use Twitter? I'd like to follow you if that would be okay. I'm absolutely enjoying your blog and look forward to new posts.

  2. discount flights

    Wonderful beat ! I would like to apprentice while you amend your website, how could i subscribe for a blog website? The account helped me a acceptable deal. I had been a little bit acquainted of this your broadcast provided bright clear idea

  3. flight ticket

    These are genuinely great ideas in concerning blogging. You have touched some fastidious things here. Any way keep up wrinting.

  4. flight ticket

    Hello there! Do you know if they make any plugins to help with SEO? I'm trying to get my blog to rank for some targeted keywords but I'm not seeing very good results. If you know of any please share. Kudos!

  5. super cheap flights

    Hi there to all, it's in fact a fastidious for me to pay a visit this web page, it contains valuable Information.

  6. cheapest flights guaranteed

    If some one desires expert view concerning blogging and site-building afterward i suggest him/her to pay a quick visit this webpage, Keep up the good job.

  7. cheap flights booking

    I am really impressed with your writing skills and also with the layout on your weblog. Is this a paid theme or did you customize it yourself? Either way keep up the excellent quality writing, it is rare to see a nice blog like this one nowadays.

  8. last minute flights

    Right now it looks like Expression Engine is the top blogging platform available right now. (from what I've read) Is that what you are using on your blog?

  9. This is very interesting, You're a very skilled blogger. I've joined your feed and look forward to seeking more of your fantastic post. Also, I've shared your web site in my social networks!

  10. cheap flights booking

    Hey there, You have done an incredible job. I will certainly digg it and personally suggest to my friends. I'm confident they'll be benefited from this site.

  11. fly cheap

    It's an awesome article in support of all the online visitors; they will obtain advantage from it I am sure.

  12. flight ticket

    This post gives clear idea in support of the new visitors of blogging, that in fact how to do blogging.

  13. plane ticket

    I just couldn't leave your web site before suggesting that I actually enjoyed the standard info an individual provide for your visitors? Is gonna be again often in order to inspect new posts

  14. extremely low airfares

    Your means of describing all in this article is in fact fastidious, all be able to easily be aware of it, Thanks a lot.

  15. cheapest airfare guaranteed

    Every weekend i used to pay a visit this website, because i wish for enjoyment, since this this site conations actually good funny information too.

  16. gamefly

    of course like your web-site however you need to check the spelling on several of your posts. Many of them are rife with spelling problems and I in finding it very troublesome to tell the reality however I'll surely come back again.

发表评论

人生在世,错别字在所难免,无需纠正。

插入图片
s
返回顶部