PHP 实现代码复用的一个方法 traits新特性
《PHP实例:PHP 实现代码复用的一个方法 traits新特性》要点: 在阅读yii2源码的时候接触到了trait,就学习了一下,写下博客记录一下.PHP实战 自 PHP 5.4.0 起,PHP 实现了代码复用的一个办法,称为 traits.PHP实战 Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制.Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用办法集.Traits 和类组合的语义是定义了一种方式来减少复杂性,避免传统多继承和混入类(Mixin)相关的典型问题.PHP实战 Trait 和一个类相似,但仅仅旨在用细粒度和一致的方式来组合功能.Trait 不能通过它自身来实例化.它为传统继承增加了水平特性的组合;也就是说,应用类的成员不需要继承.PHP实战 Trait 示例PHP实战
代码如下:
<?php trait ezcReflectionReturnInfo { ??? function getReturnType() { /*1*/ } ??? function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod { ??? use ezcReflectionReturnInfo; ??? /* ... */ } class ezcReflectionFunction extends ReflectionFunction { ??? use ezcReflectionReturnInfo; ??? /* ... */ } ?> 优先级 从基类继承的成员被 trait 插入的成员所覆盖.优先顺序是来自当前类的成员覆盖了 trait 的办法,而 trait 则覆盖了被继承的办法.PHP实战 优先顺序示例PHP实战
代码如下:
<?php class Base { ??? public function sayHello() { ??????? echo 'Hello '; ??? } } trait SayWorld { ??? public function sayHello() { ??????? parent::sayHello(); ??????? echo 'World!'; ??? } } class MyHelloWorld extends Base { ??? use SayWorld; } $o = new MyHelloWorld(); $o->sayHello(); ?> 以上例程会输出:Hello World!PHP实战 从基类继承的成员被插入的 SayWorld Trait 中的 sayHello 办法所覆盖.其行为 MyHelloWorld 类中定义的办法一致.优先顺序是当前类中的办法会覆盖 trait 办法,而 trait 办法又覆盖了基类中的办法.PHP实战 另一个优先级顺序的例子PHP实战
代码如下:
<?php trait HelloWorld { ??? public function sayHello() { ??????? echo 'Hello World!'; ??? } } class TheWorldIsNotEnough { ??? use HelloWorld; ??? public function sayHello() { ??????? echo 'Hello Universe!'; ??? } } $o = new TheWorldIsNotEnough(); $o->sayHello(); ?> 以上例程会输出:Hello Universe!PHP实战 多个 trait 通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中.PHP实战 多个 trait 的用法的例子PHP实战
代码如下:
<?php 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(); ?> 以上例程会输出:Hello World!PHP实战 冲突的办理 如果两个 trait 都插入了一个同名的办法,如果没有明确解决冲突将会产生一个致命错误.PHP实战 为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突办法中的哪一个.PHP实战 以上方式仅允许排除掉其它办法,as 操作符可以将其中一个冲突的办法以另一个名称来引入.PHP实战 冲突办理的例子PHP实战
代码如下:
<?php trait A { ??? public function smallTalk() { ??????? echo 'a'; ??? } ??? public function bigTalk() { ??????? echo 'A'; ??? } } trait B { ??? public function smallTalk() { ??????? echo 'b'; ??? } ??? public function bigTalk() { ??????? echo 'B'; ??? } } class Talker { ??? use A,B { ??????? B::smallTalk insteadof A; ??????? A::bigTalk insteadof B; ??? } } class Aliased_Talker { ??? use A,B { ??????? B::smallTalk insteadof A; ??????? A::bigTalk insteadof B; ??????? B::bigTalk as talk; ??? } } ?> 在本例中 Talker 使用了 trait A 和 B.由于 A 和 B 有冲突的办法,其定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk.PHP实战 Aliased_Talker 使用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名.PHP实战 修改方法的拜访控制 使用 as 语法还可以用来调整方法的拜访控制.PHP实战 修改方法的拜访控制的例子PHP实战
代码如下:
<?php trait HelloWorld { ??? public function sayHello() { ??????? echo 'Hello World!'; ??? } } // 修改 sayHello 的拜访控制 class MyClass1 { ??? use HelloWorld { sayHello as protected; } } // 给方法一个改变了拜访控制的别名 // 原版 sayHello 的拜访控制则没有发生变化 class MyClass2 { ??? use HelloWorld { sayHello as private myPrivateHello; } } ?> 从 trait 来组成 trait 正如类能够使用 trait 一样,其它 trait 也能够使用 trait.在 trait 定义时通过使用一个或多个 trait,它能够组合其它 trait 中的部分或全部成员.PHP实战 从 trait 来组成 trait的例子PHP实战
代码如下:
<?php 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(); ?> 以上例程会输出:Hello World!PHP实战 Trait 的抽象成员 为了对使用的类施加强制要求,trait 支持抽象办法的使用.PHP实战 表示通过抽象办法来进行强制要求的例子PHP实战
代码如下:
<?php 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; ??? } } ?> Trait 的静态成员 Traits 可以被静态成员静态办法定义.PHP实战 静态变量的例子PHP实战
代码如下:
<?php trait Counter { ??? public function inc() { ??????? static $c = 0; ??????? $c = $c + 1; ??????? echo "$cn"; ??? } } class C1 { ??? use Counter; } class C2 { ??? use Counter; } $o = new C1(); $o->inc(); // echo 1 $p = new C2(); $p->inc(); // echo 1 ?> 静态办法的例子PHP实战
代码如下:
<?php trait StaticExample { ??? public static function doSomething() { ??????? return 'Doing something'; ??? } } class Example { ??? use StaticExample; } Example::doSomething(); ?> 静态变量和静态办法的例子PHP实战
代码如下:
<?php trait Counter { ??? public static $c = 0; ??? public static function inc() { ??????? self::$c = self::$c + 1; ??????? echo self::$c . "n"; ??? } } class C1 { ??? use Counter; } class C2 { ??? use Counter; } C1::inc(); // echo 1 C2::inc(); // echo 1 ?> 属性 定义属性的例子PHP实战
代码如下:
<?php trait PropertiesTrait { ??? public $x = 1; } class PropertiesExample { ??? use PropertiesTrait; } $example = new PropertiesExample; $example->x; ?> 如果 trait 定义了一个属性,那类将不能定义同样名称的属性,否则会产生一个错误.如果该属性在类中的定义与在 trait 中的定义兼容(同样的可见性和初始值)则错误的级别是 E_STRICT,否则是一个致命错误.PHP实战 冲突的例子PHP实战
代码如下:
<?php trait PropertiesTrait { ??? public $same = true; ??? public $different = false; } class PropertiesExample { ??? use PropertiesTrait; ??? public $same = true; // Strict Standards ??? public $different = true; // 致命错误 } ?> Use的不同 不同use的例子PHP实战
代码如下:
<?php namespace FooBar; use FooTest;? // means FooTest - the initial is optional ?> <?php namespace FooBar; class SomeClass { ??? use FooTest;?? // means FooBarFooTest } ?> 第一个use是用于 namespace 的 use FooTest,找到的是 FooTest,第二个 use 是使用一个trait,找到的是FooBarFooTest.PHP实战 __CLASS__和__TRAIT__ 示例如下PHP实战
代码如下:
<?php trait TestTrait { ??? public function testMethod() { ??????? echo "Class: " . __CLASS__ . PHP_EOL; ??????? echo "Trait: " . __TRAIT__ . PHP_EOL; ??? } } class BaseClass { ??? use TestTrait; } class TestClass extends BaseClass { } $t = new TestClass(); $t->testMethod(); //Class: BaseClass //Trait: TestTrait Trait单例 实例如下PHP实战
代码如下:
<?php trait singleton {??? ??? /** ???? * private construct,generally defined by using class ???? */ ??? //private function __construct() {} ??? public static function getInstance() { ??????? static $_instance = NULL; ??????? $class = __CLASS__; ??????? return $_instance ?: $_instance = 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); ??? } } /** * Example Usage */ class foo { ??? use singleton; ??? private function __construct() { ??????? $this->name = 'foo'; ??? } } class bar { ??? use singleton; ??? private function __construct() { ??????? $this->name = 'bar'; ??? } } $foo = foo::getInstance(); echo $foo->name; $bar = bar::getInstance(); echo $bar->name; 调用trait办法PHP实战 虽然不很明显,但是如果Trait的办法可以被定义为在普通类的静态办法,就可以被调用PHP实战 实例如下
代码如下:
<?php trait Foo { ??? function bar() { ??????? return 'baz'; ??? } } echo Foo::bar(),"n"; ?> 小伙伴们对于traits的新特性是否熟悉了呢,希望本文能对大家有所赞助.PHP实战 编程之家培训学院每天发布《PHP实例:PHP 实现代码复用的一个方法 traits新特性》等实战技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培养人才。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |