zoukankan      html  css  js  c++  java
  • php之trait-实现多继承

    PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法。php的Traits和Go语言的组合功能类似,通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。具体用法请看下面的代码:

     1 <?php
     2     trait Drive {
     3         public $carName = 'trait';
     4         public function driving() {
     5             echo "driving {$this->carName}
    ";
     6         }
     7     }
     8     class Person {
     9         public function eat() {
    10             echo "eat
    ";
    11         }
    12     }
    13     class Student extends Person {
    14         use Drive;
    15         public function study() {
    16             echo "study
    ";
    17         }
    18     }
    19     $student = new Student();
    20     $student->study();
    21     $student->eat();
    22     $student->driving();

    输出结果如下:

    1 study
    2 eat
    3 driving trait

    上面的例子中,Student类通过继承Person,有了eat方法,通过组合Drive,有了driving方法和属性carName。

    如果Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢?通过下面的代码测试一下:

     1 <?php 
     2     trait Drive {
     3         public function hello() {
     4             echo "hello drive
    ";
     5         }
     6         public function driving() {
     7             echo "driving from drive
    ";
     8         }
     9     }
    10     class Person {
    11         public function hello() {
    12             echo "hello person
    ";
    13         }
    14         public function driving() {
    15             echo "driving from person
    ";
    16         }
    17     }
    18     class Student extends Person {
    19         use Drive;
    20         public function hello() {
    21             echo "hello student
    ";
    22         }
    23     }
    24     $student = new Student();
    25     $student->hello();
    26     $student->driving();

    输出结果如下:

    1 hello student
    2 driving from drive

    因此得出结论:当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法。

    如果要组合多个Trait,通过逗号分隔 Trait名称:

    1 use Trait1, Trait2;

    如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误。

     1 <?php
     2 trait Trait1 {
     3     public function hello() {
     4         echo "Trait1::hello
    ";
     5     }
     6     public function hi() {
     7         echo "Trait1::hi
    ";
     8     }
     9 }
    10 trait Trait2 {
    11     public function hello() {
    12         echo "Trait2::hello
    ";
    13     }
    14     public function hi() {
    15         echo "Trait2::hi
    ";
    16     }
    17 }
    18 class Class1 {
    19     use Trait1, Trait2;
    20 }

    输出结果如下:

    1 PHP Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in ~/php54/trait_3.php on line 20

    使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码:

     1 <?php
     2 trait Trait1 {
     3     public function hello() {
     4         echo "Trait1::hello
    ";
     5     }
     6     public function hi() {
     7         echo "Trait1::hi
    ";
     8     }
     9 }
    10 trait Trait2 {
    11     public function hello() {
    12         echo "Trait2::hello
    ";
    13     }
    14     public function hi() {
    15         echo "Trait2::hi
    ";
    16     }
    17 }
    18 class Class1 {
    19     use Trait1, Trait2 {
    20         Trait2::hello insteadof Trait1;
    21         Trait1::hi insteadof Trait2;
    22     }
    23 }
    24 class Class2 {
    25     use Trait1, Trait2 {
    26         Trait2::hello insteadof Trait1;
    27         Trait1::hi insteadof Trait2;
    28         Trait2::hi as hei;
    29         Trait1::hello as hehe;
    30     }
    31 }
    32 $Obj1 = new Class1();
    33 $Obj1->hello();
    34 $Obj1->hi();
    35 echo "
    ";
    36 $Obj2 = new Class2();
    37 $Obj2->hello();
    38 $Obj2->hi();
    39 $Obj2->hei();
    40 $Obj2->hehe();

    输出结果如下:

    1 Trait2::hello
    2 Trait1::hi
    3 
    4 Trait2::hello
    5 Trait1::hi
    6 Trait2::hi
    7 Trait1::hello

    as关键词还有另外一个用途,那就是修改方法的访问控制:

     1 <?php
     2     trait Hello {
     3         public function hello() {
     4             echo "hello,trait
    ";
     5         }
     6     }
     7     class Class1 {
     8         use Hello {
     9             hello as protected;
    10         }
    11     }
    12     class Class2 {
    13         use Hello {
    14             Hello::hello as private hi;
    15         }
    16     }
    17     $Obj1 = new Class1();
    18     $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的
    19     $Obj2 = new Class2();
    20     $Obj2->hello(); # 原来的hello方法仍然是公共的
    21     $Obj2->hi();  # 报致命错误,因为别名hi方法被修改成私有的

    Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:

     1 <?php
     2 trait Hello {
     3     public function sayHello() {
     4         echo "Hello
    ";
     5     }
     6 }
     7 trait World {
     8     use Hello;
     9     public function sayWorld() {
    10         echo "World
    ";
    11     }
    12     abstract public function getWorld();
    13     public function inc() {
    14         static $c = 0;
    15         $c = $c + 1;
    16         echo "$c
    ";
    17     }
    18     public static function doSomething() {
    19         echo "Doing something
    ";
    20     }
    21 }
    22 class HelloWorld {
    23     use World;
    24     public function getWorld() {
    25         return 'get World';
    26     }
    27 }
    28 $Obj = new HelloWorld();
    29 $Obj->sayHello();
    30 $Obj->sayWorld();
    31 echo $Obj->getWorld() . "
    ";
    32 HelloWorld::doSomething();
    33 $Obj->inc();
    34 $Obj->inc();

    输出结果如下:

    1 Hello
    2 World
    3 get World
    4 Doing something
    5 1
    6 2

    转载自:http://tabalt.net/blog/php-traits/

  • 相关阅读:
    unity3d 打包个人记录
    Unity3d 协程
    Unity3d 复制文字到剪切板及存储图像到相册
    为什么 redo log 具有 crash-safe 的能力,是 binlog 无法替代的?
    Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
    深入理解Java虚拟机1——内存区域
    Java源码系列3——LinkedHashMap
    深入理解Java虚拟机2——对象探秘
    高效学习
    WordPress自动代码高亮
  • 原文地址:https://www.cnblogs.com/justdoyou/p/7116621.html
Copyright © 2011-2022 走看看