zoukankan      html  css  js  c++  java
  • PHP中的Traits用法详解

    PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法。php的Traits和Go语言的组合功能有点类似,

    通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。具体用法请看下面的代码:

    <?php
    trait Drive {
        public $carName = 'BMW';
        public function driving() {
            echo "driving {$this->carName}
    ";
        }
    }
    class Person {
        public function age() {
            echo "i am 18 years old
    ";
        }
    }
    class Student extends Person {
        use Drive;
        public function study() {
            echo "Learn to drive 
    ";
        }
    }
    $student = new Student();
    $student->study();
    $student->age();
    $student->driving();
    Learn to drive 
    i am 18 years old
    driving BMW

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

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

    <?php
    trait Drive {
        public function hello() {
            echo "hello 周伯通
    ";
        }
        public function driving() {
            echo "周伯通不会开车
    ";
        }
    }
    class Person {
        public function hello() {
            echo "hello 大家好
    ";
        }
        public function driving() {
            echo "大家都会开车
    ";
        }
    }
    class Student extends Person {
        use Drive;//trait 的方法覆盖了基类Person中的方法,所以Person中的hello 和driving被覆盖
        public function hello() {
            echo "hello 新学员
    ";//当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,所以此处hello会覆盖trait中的hello
        }
    }
    $student = new Student();
    $student->hello();
    $student->driving();
    hello 新学员
    周伯通不会开车

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

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

    use Trait1, Trait2;

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

    <?php
    trait Trait1 {
        public function hello() {
            echo "Trait1::hello
    ";
        }
        public function hi() {
            echo "Trait1::hi
    ";
        }
    }
    trait Trait2 {
        public function hello() {
            echo "Trait2::hello
    ";
        }
        public function hi() {
            echo "Trait2::hi
    ";
        }
    }
    class Class1 {
        use Trait1, Trait2;
    }
    //输出:Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in

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

    <?php
    trait Trait1 {
        public function hello() {
            echo "Trait1::hello 
    ";
        }
        public function hi() {
            echo "Trait1::hi 
    ";
        }
    }
    trait Trait2 {
        public function hello() {
            echo "Trait2::hello
    ";
        }
        public function hi() {
            echo "Trait2::hi
    ";
        }
    }
    class Class1 {
        use Trait1, Trait2 {
            Trait2::hello insteadof Trait1;
            Trait1::hi insteadof Trait2;
        }
    }
    class Class2 {
        use Trait1, Trait2 {
            Trait2::hello insteadof Trait1;
            Trait1::hi insteadof Trait2;
            Trait2::hi as hei;
            Trait1::hello as hehe;
        }
    }
    $Obj1 = new Class1();
    $Obj1->hello();
    $Obj1->hi();
    echo "
    ";
    $Obj2 = new Class2();
    $Obj2->hello();
    $Obj2->hi();
    $Obj2->hei();
    $Obj2->hehe();
    Trait2::hello
    Trait1::hi 
    
    Trait2::hello
    Trait1::hi 
    Trait2::hi
    Trait1::hello 

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

    <?php
    trait Hello {
        public function hello() {
            echo "hello,我是周伯通
    ";
        }
    }
    class Class1 {
        use Hello {
            hello as protected;
        }
    }
    class Class2 {
        use Hello {
            Hello::hello as private hi;
        }
    }
    $Obj1 = new Class1();
    $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的
    $Obj2 = new Class2();
    $Obj2->hello(); # 输出: hello,我是周伯通,因为原来的hello方法仍然是公共的
    $Obj2->hi();  # 报致命错误,因为别名hi方法被修改成私有的
    Uncaught Error: Call to protected method Class1::hello() from context '' in D:webmytestp.php:18

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

    <?php
    trait Hello {
        public function sayHello() {
            echo "Hello 我是周伯通
    ";
        }
    }
    trait World {
        use Hello;
        public function sayWorld() {
            echo "hello world
    ";
        }
        abstract public function getWorld();
        public function inc() {
            static $c = 0;
            $c = $c + 1;
            echo "$c
    ";
        }
        public static function doSomething() {
            echo "Doing something
    ";
        }
    }
    class HelloWorld {
        use World;
        public function getWorld() {
            return 'do you get World ?';
        }
    }
    $Obj = new HelloWorld();
    $Obj->sayHello();
    $Obj->sayWorld();
    echo $Obj->getWorld() . "
    ";
    HelloWorld::doSomething();
    $Obj->inc();
    $Obj->inc();
    Hello 我是周伯通
    hello world
    do you get World ?
    Doing something
    1
    2
  • 相关阅读:
    6-8 Percolate Up and Down (20分)
    6-7 Isomorphic (20分)
    6-5 Evaluate Postfix Expression (25分)
    服务器磁盘满无法释放空间解析及解决
    必会的MySQL操作方法
    Tomcat基本安装和优化方法
    Nginx常用配置及优化安全
    Redis笔记整理(三):进阶操作与高级部分
    Redis笔记整理(二):Java API使用与Redis分布式集群环境搭建
    Redis笔记整理(一):Redis安装配置与数据类型操作
  • 原文地址:https://www.cnblogs.com/phpper/p/8978098.html
Copyright © 2011-2022 走看看