<?php /** * Created by PhpStorm. * User: YANGHY * Date: 2020/4/29 * Time: 10:21 */ /** * Class TestTrait * Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。 * Trait 为了减少单继承语言的限制,在不同层次结构内独立的类中复用 method。 * Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。 * 优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。 * */ //例子1 单个trait的使用 /**trait TraitExample{ public function add($a,$b){ return $a + $b; } public function sub($a, $b){ return $a - $b; } } class TestTrait { use TraitExample; // 使用trait } $obj = new TestTrait(); echo $obj->add(10,12)."\n"; echo $obj->sub(12,2);**/ //例子2 优先级 //trait TraitExample{ // public function add($a,$b){ // return $a + $b; // } // public function sub($a, $b){ // return $a - $b; // } //} //class Count{ // public function add($a,$b){ // return $a + $b + 100; // } // public function sub($a, $b){ // return $a - $b + 100; // } //} //class TestTrait extends Count //{ // public function add($a,$b){ // return $a + $b + 200; // } // public function sub($a, $b){ // return $a - $b + 200; // } // use TraitExample; // 使用trait //} //$obj = new TestTrait(); //echo $obj ->add(10,10)."\n"; // 220 //echo $obj ->sub(10,10); // 200 // 例子3 多个trait通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。 /*trait Ex1{ public function say(){ echo "hello"; } } trait Ex2{ public function reply(){ echo "hi"; } } class Test{ use Ex1,Ex2; // 引用多个trait } $obj = new Test(); $obj ->say(); echo "\n"; $obj ->reply();*/ // 4.多个trait中同名函数冲突解决方法 // insteadof 明确使用哪一个 /*trait Ex1{ public function say(){ echo "Ex1 say hello"; } public function replay(){ echo "Ex1 reply hi"; } } trait Ex2{ public function say(){ echo "Ex2 say hello"; } public function replay(){ echo "Ex2 reply hi"; } } class Test{ use Ex1,Ex2{ Ex2::say insteadof Ex1; // 使用 insteadof明确使用哪个 例如使用Ex2的say Ex1::replay insteadof Ex2; // 使用 Ex1的replay } // 引用多个trait } $obj = new Test(); $obj ->say(); // Ex2 say hello echo "\n"; $obj ->replay(); // Ex1 reply hi*/ // as 引入别名 /*trait Ex1{ public function say(){ echo "Ex1 say hello"; } public function replay(){ echo "Ex1 reply hi"; } } trait Ex2{ public function say(){ echo "Ex2 say hello"; } public function replay(){ echo "Ex2 reply hi"; } } class Test{ use Ex1,Ex2{ Ex1::say insteadof Ex2; Ex1::replay insteadof Ex2; Ex2::say as Esay; Ex2::replay as Ereplay; } // 引用多个trait } $obj = new Test(); $obj ->say(); // Ex1 say hello echo "\n"; $obj ->replay(); // Ex1 reply hi echo "\n"; $obj ->Esay(); // Ex2 say hello echo "\n"; $obj ->Ereplay(); // Ex2 say hi*/ // 修改方法的访问控制权限 /*trait Control{ public function getC(){ echo "public"; } } class Test{ use Control{ // getC as private; // 修改方法权限 getC as private getByC;//原版 getC 的访问控制并没有发生变化,生成的新的getByC控制权限为private } public function getControl($className,$method){ $reflection = new ReflectionMethod($className,$method); $result = Reflection::getModifierNames($reflection->getModifiers()); print_r($result); } } // $obj = new Test(); // Array // ( // [0] => private // ) $obj ->getControl(‘Test‘,‘getC‘); $obj ->getControl(‘Test‘,‘getbyC‘); */ //trait组成trait /*trait Hello{ public function hello(){ echo "hello"; } } trait World{ public function world(){ echo "world"; } } trait HelloWorld{ use Hello,World; } class MyHelloWorld{ use HelloWorld; } $obj = new MyHelloWorld(); $obj ->hello(); echo " "; $obj ->world();*/ //trait的抽象成员 为了对使用的类强制要求,trait支持抽象方法的使用 /*trait Hello{ public function sayHello(){ echo "hello ".$this->getWorld(); } abstract function getWorld(); } class Test{ use Hello; private $world; function getWorld() { return $this->world; } function setWorld($value){ $this ->world = $value; } } $obj = new Test(); $obj ->setWorld("world!"); $obj ->sayHello();*/ // trait 可以被静态成员和静态方法定义 /*trait StaticVf{ static $a = ‘kral‘; static public function say(){ echo "今天的天气可真好!"; } } class Test{ use StaticVf; } echo Test::$a; Test::say();*/ // trait Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。 // 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。 在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。 /*trait StaticV{ public $a = true; public $b = false; } class Test{ use StaticV; public $a = "hello"; // Fatal error 测试版本php 7.3.1 public $b = false; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒 } $obj = new Test();*/ // 与继承不同;如果trait具有静态属性,则使用该trait的每个类都具有这些属性的独立实例。 // 继承 /*class StaticV{ static $a; } class TestStaticv extends StaticV{ } class TestStaticv2 extends StaticV{ } TestStaticv::$a = ‘hello‘; TestStaticv2::$a = ‘world‘; echo TestStaticv::$a.‘ ‘.TestStaticv2::$a; // World World*/ /*trait StaticV{ static $a; } class TestTrait{ use StaticV; } class TestTrait2{ use StaticV; } TestTrait::$a = ‘hello‘; TestTrait2::$a = ‘world‘; echo TestTrait::$a.‘ ‘.TestTrait2::$a; // hello world*/ // __CLASS__ 返回使用trait的类的名称,不是调用trait方法的类 /*trait MyTrait{ public function TestTrait(){ echo "CLASS: ".__CLASS__; echo "TRAIT: ".__TRAIT__; } } class BaseClass{ use MyTrait; } class TestBaseClass extends BaseClass{ } $obj = new TestBaseClass(); $obj ->TestTrait();*/ // traits与继承的另一个区别是,traits中定义的方法可以访问它们使用的类的方法和属性,包括私有类。 /*trait MyTrait{ protected function setVar(){ return $this ->var; } } class TraitUser{ use MyTrait; private $var = ‘var‘; public function getVar() { return $this ->setVar($this->var); } } $obj = new TraitUser(); echo $obj->getVar();*/ // 如前所述,trait中的静态属性和方法可以使用trait直接访问。由于trait是语言辅助的c/p, //您应该注意,trait中的静态属性将被初始化为trait属性在类声明时的值。 /*trait Base{ protected static $a = ‘Right‘; public static function printed(){ echo static::$a.PHP_EOL; } public static function setType($value){ static::$a = $value; } } class Test{ use Base; } Base::setType(‘Left‘); class Test2{ use Base; } Base::setType(‘Center‘); Base::printed(); Test::printed(); Test2::printed();*/ // 魔术方法__call 按预期工作 // PHP5 的对象新增了一个专用方法 __call(), // 这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在或被权限控制中的方法,__call 方法将会被自动调用. /*trait Base{ public function __call($name, $arguments) { return count($arguments); } } class TestTrait{ use Base; } $obj = new TestTrait(); echo $obj ->go(1,2,3);*/ // trait单例 /*trait Singleton{ public static function getSingleton(){ static $singleton = NULL; $class = __CLASS__; return $singleton?$singleton:new $class; } public function __clone() { trigger_error(‘Cloning ‘.__CLASS__.‘ is not allowed.‘,E_USER_ERROR); } public function __wakeup() { trigger_error(‘Unserializing ‘.__CLASS__.‘ is not allowed.‘,E_USER_ERROR); } } class Test{ use Singleton; private function __construct() { $this ->name =‘Test‘; } } class Test2{ use Singleton; private function __construct() { $this->name = ‘Test2‘; } } $test = Test::getSingleton(); var_dump($test); //$test11 = Test::getSingleton(); //var_dump($test11); echo $test->name; $test2 = Test2::getSingleton(); echo $test2 ->name; var_dump($test2);*/
原文:https://www.cnblogs.com/kral-yang/p/12812708.html