zoukankan      html  css  js  c++  java
  • trait

    参考

    引文

    在php中,为实现代码复用,有了继承,但是一个类只能继承一个父类,不支持多继承,接口支持多实现,但是接口又不太一样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑,严格意义上来说,不算代码复用,从php5.4开始,php实现了另外一种代码复用的方法,就是下文即将要说的trait。

    trait

    trait是为扩展类似php单继承的一种代码复用机制,解除单继承语言的限制,使开发人员能够自由地在不同层次结构中组合复用method。trait本身不能实例化,它依托于class存在。传统继承是上下层面的关系,trait则为水平层面的组合。

    优先级

    对于相同方法名的方法而言,当前类的方法覆盖trait方法,trait中方法覆盖继承的父类方法

    class Base {
        public function sayHello() {
            echo 'Hello ';
        }
    }
    
    trait SayWorld {
        public function sayHello() {
            parent::sayHello();
            echo 'World!';
        }
        
        public function sayPeter() {
            echo "
    hello trait peter
    ";
        }
    }
    
    class MyHelloWorld extends Base {
        use SayWorld;
        public function sayPeter() {
            echo "
    hello class peter
    ";
        }
    }
    
    $o = new MyHelloWorld();
    $o->sayHello();
    $o->sayPeter();

    输出

     多个trait

    在类中,可以声明多个trait,将多个trait组合到一个类中

    trait Hello {
        public function sayHello() {
            echo 'Hello ';
        }
    }
    
    trait World {
        public function sayWorld() {
            echo 'World';
        }
    }
    
    class MyHelloWorld {
        use Hello, World;
        public function sayExclamationMark() {
            echo '!';
        }
    }
    
    $o = new MyHelloWorld();
    $o->sayHello();
    $o->sayWorld();
    $o->sayExclamationMark();

    输出

    trait冲突

    如果trait之间定义了同名的方法,类中又组合了有同名方法的trait,会出现命名冲突,这个时候可以使用insteadof指明调用冲突方法中的某一个。trait中可以用as操作符为某个方法引入别名,注意引入别名并不会对原方法重命名,别名不能和已包含的trait中方法名重复

    trait A {
        public function smallTalk() {
            echo 'a';
        }
        public function bigTalk() {
            echo 'A';
        }
        public function helloPeter() {
            echo "hello peter
    ";
        }
    }
    
    trait B {
        public function smallTalk() {
            echo 'b';
        }
        public function bigTalk() {
            echo 'B';
        }
        public function helloAlice() {
            echo "hello alice
    ";
        }
    }
    
    class Talker {
        use A, B {
            B::smallTalk insteadof A;
            A::bigTalk insteadof B;
        }
    }
    
    class TalkerAs {
        use A, B {
            B::smallTalk insteadof A;
            A::bigTalk insteadof B;
            B::bigTalk as talk;
        }
    }
    
    class TalkerHello {
        use A, B {
            B::smallTalk insteadof A;
            A::bigTalk insteadof B;
            // A::helloPeter as helloAlice; 别名不允许和已包含trait中方法重名
        }
    }
    
    $talker = new Talker();
    $talker->smallTalk();
    $talker->bigTalk();
    echo "
    ";
    $talkerAs = new TalkerAs();
    $talkerAs->smallTalk();
    $talkerAs->bigTalk();
    $talkerAs->talk();

    输出

    trait组合trait

    正如class可以使用多个trait,trait也可以使用trait

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

    输出

    抽象成员方法

    在trait中可以定义抽象方法,类中如果要使用trait,必须要实现trait中的抽象方法

    trait Hello {
        public function sayHelloWorld() {
            echo 'Hello ' . $this->getWorld() . "
    ";
        }
        abstract public function getWorld();
    }
    
    class MyHelloWorld {
        private $world;
        use Hello;
        public function getWorld() {
            return $this->world;
        }
        public function setWorld($val) {
            $this->world = $val;
        }
    }
    
    $o = new MyHelloWorld();
    $o->sayHelloWorld();
    $o->setWorld('world');
    $o->sayHelloWorld();

    输出

     属性

    trait中也可以定义属性,但要注意trait定了某个属性后,使用该trait的类中就不能定义同样名称的属性,否则会产生fatal error。(属性如果是兼容的(同样的访问控制符和默认值),就不会产生fatal error,但在php7之前,会有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; // 致命错误
    }

    php5.6

    php7.1

  • 相关阅读:
    如何解决无法成功git commit 和git push
    orleans 项目调试注意
    silo 主机 配置
    asp.net core 项目引用包版本问题
    C# async 方法怎么被正确的消费 (新篇)
    C# 虚方法 复习
    C# dynamic 适用场景进一步说明
    [MySQL]
    C# Subject 观察者模式
    C# 协变与逆变
  • 原文地址:https://www.cnblogs.com/peter-yan/p/8404809.html
Copyright © 2011-2022 走看看