zoukankan      html  css  js  c++  java
  • php中trait

    1.简介

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

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

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

    trait的类不能实例化;

    1.2 优先级

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

    //基类
    class Base{
        public function sayHello(){
            echo "base Hello";
        }
    }
    // trait 类
    trait SayWorld{
    
        public function sayHello(){
            echo "trait Hello";
        }
    }
    //
    class MyHello extends Base{
        use SayWorld;
    }
    
    $obj = new MyHello();
    $obj->sayHello();

    // 结果:trait Hello

    1.3 多个trait

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

    //基类
    class Base{
        public function sayHello(){
            echo "base Hello";
        }
    }
    // trait 类
    trait SayWorld{
    
        public function sayHello(){
            echo "trait Hello";
        }
    }
    trait World{
        public function sayWorld(){
            echo 'trait World';
        }
    }
    //
    class MyHello extends Base{
        use SayWorld,World;
        public function sayHello(){
            echo "MyHello Hello";
        }
    }
    
    $obj = new MyHello();
    $obj->sayHello();
    echo '<br/>';
    $obj->sayWorld();
    //结果:
    MyHello Hello
    trait World

    1.4 trait 冲突的解决 

    如果两个 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 的别名

    trait A{
        public function small(){
            echo 'a';
        }
        public function big(){
            echo 'A';
        }
        public function mid(){
            echo 'mid';
        }
    }
    trait B{
        public function small(){
            echo 'b';
        }
        public function big(){
            echo 'B';
        }
    }
    
    class Talker{
        use A,B {
            B::small insteadof A;//small 方法使用B中的方法
            A::big insteadof B;
            A::mid insteadof B;
            B::big as talk;
        }
    }
    
    $obj = new Talker();
    $obj->talk();

    1.5 修改方法的访问控制

    trait Hello{
        public function sayHello(){
            echo 'Hello';
        }
    }
    
    class MyHello{
        use Hello{
            sayHello as protected;//修改访问权限
            // sayHello as b  // 起个别名
        }
    }
    
    class Myclass{
        use Hello{
            sayHello as private pHello; //修改访问权限的别名
        }
    }
    $obj = new Myclass();
    
    $obj->sayHello();

    1.6 从trait来组成trait

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

    trait Hello{
        public function say(){
            echo 'Hello';
        }
    }
    
    trait World{
        public function sayWorld(){
            echo 'World';
        }
    }
    
    trait HelloWorld{
        use Hello,World;
    }
    
    class MyHelloWorld{
        use HelloWorld;
    }
    
    $obj = new MyHelloWorld();
    
    $obj->sayWorld();

    1.7 trait的抽象成员

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

    trait Hello{
        public function say(){
            echo 'Hello';
        }
        abstract public function get();
    }
    
    
    
    class MyHelloWorld{
        use Hello;
        // trait中的抽象方法,必须实现
        public function get(){
            echo "Hello World";
        }
    }
    
    $obj = new MyHelloWorld();
    
    $obj->say();

    1.8 静态成员

    trait Counter{
        public $num = 1;
        public function inc(){
            static $c = 0;
            $c++;
            echo $c;
            $this->num = 2;
        }
        // 静态方法
        public static function get(){
            echo 'vic';
        }
    }
    
    class C1{
        use Counter;
    }
    $obj = new C1();
    
    $obj->inc(); //1
    $obj->inc();// 2
    C1::get();//vic
    Counter::get();//trait不可以实例化,但是静态方法可以调用
    $obj = new C1();
    
    $obj->inc();//3
    
    class C2{
        use Counter;
    }
    
    $obj = new C2();
    $obj->inc();//1
    echo $obj->num;//2

    1.9 属性

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

    在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。

    trait PropertiesTrait {
        public $same = true;
        public $different = false;
    }
    
    class PropertiesExample {
        use PropertiesTrait;
        public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
        public $different = true; // 致命错误
    }

    1.10 trait 静态化

    trait Counter{
        public $num = 1;
        public function inc(){
            static $c = 0;
            $c++;
            echo $c;
            $this->num = 2;
        }
        // 静态方法
        public static function get(){
            return new static();//不是new的trait,是new的调用者
        }
    }

    参考资料:http://php.net/manual/zh/language.oop5.traits.php

            https://www.cnblogs.com/CraryPrimitiveMan/p/4162738.html

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    Atitit 趋势管理之道 attilax著
    Atitit 循环处理的新特性 for...else...
    Atitit 2017年的技术趋势与未来的大技术趋势
    atitit 用什么样的维度看问题.docx 如何了解 看待xxx
    atitit prj mnrs 项目中的几种经理角色.docx
    Atitit IT办公场所以及度假村以及网点以及租房点建设之道 attilax总结
    Atitit 工具选型的因素与方法 attilax总结
    Atitit.团队文化建设影响组织的的一些原理 法则 定理 效应 p826.v4
    Atiitt 管理方面的误区总结 attilax总结
    Atitit 未来趋势把控的书籍 attilax总结 v3
  • 原文地址:https://www.cnblogs.com/myvic/p/8057590.html
Copyright © 2011-2022 走看看