程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> PHP的學習--Traits新特性

PHP的學習--Traits新特性

編輯:關於PHP編程

PHP的學習--Traits新特性


    自 PHP 5.4.0 起,PHP 實現了代碼復用的一個方法,稱為 traits。   Traits 是一種為類似 PHP 的單繼承語言而准備的代碼復用機制。Trait 為了減少單繼承語言的限制,使開發人員能夠自由地在不同層次結構內獨立的類中復用方法集。Traits 和類組合的語義是定義了一種方式來減少復雜性,避免傳統多繼承和混入類(Mixin)相關的典型問題。   Trait 和一個類相似,但僅僅旨在用細粒度和一致的方式來組合功能。Trait 不能通過它自身來實例化。它為傳統繼承增加了水平特性的組合;也就是說,應用類的成員不需要繼承。   Trait 示例     <?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 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!   從基類繼承的成員被插入的 SayWorld Trait 中的 sayHello 方法所覆蓋。其行為 MyHelloWorld 類中定義的方法一致。優先順序是當前類中的方法會覆蓋 trait 方法,而 trait 方法又覆蓋了基類中的方法。   另一個優先級順序的例子     <?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!   多個 trait 通過逗號分隔,在 use 聲明列出多個 trait,可以都插入到一個類中。   多個 trait 的用法的例子     <?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!   沖突的解決 如果兩個 trait 都插入了一個同名的方法,如果沒有明確解決沖突將會產生一個致命錯誤。   為了解決多個 trait 在同一個類中的命名沖突,需要使用 insteadof 操作符來明確指定使用沖突方法中的哪一個。   以上方式僅允許排除掉其它方法,as 操作符可以將其中一個沖突的方法以另一個名稱來引入。   沖突解決的例子     <?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。   Aliased_Talker 使用了 as 操作符來定義了 talk 來作為 B 的 bigTalk 的別名。   修改方法的訪問控制 使用 as 語法還可以用來調整方法的訪問控制。   修改方法的訪問控制的例子     <?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 中的部分或全部成員。   從 trait 來組成 trait的例子     <?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!   Trait 的抽象成員 為了對使用的類施加強制要求,trait 支持抽象方法的使用。   表示通過抽象方法來進行強制要求的例子   <?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 trait Counter {     public function inc() {         static $c = 0;         $c = $c + 1;         echo "$c\n";     } }   class C1 {     use Counter; }   class C2 {     use Counter; }   $o = new C1(); $o->inc(); // echo 1 $p = new C2(); $p->inc(); // echo 1 ?>   靜態方法的例子     <?php trait StaticExample {     public static function doSomething() {         return 'Doing something';     } }   class Example {     use StaticExample; }   Example::doSomething(); ?>   靜態變量和靜態方法的例子     <?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 ?>   屬性 Trait 同樣可以定義屬性。   定義屬性的例子     <?php trait PropertiesTrait {     public $x = 1; }   class PropertiesExample {     use PropertiesTrait; }   $example = new PropertiesExample; $example->x; ?>   如果 trait 定義了一個屬性,那類將不能定義同樣名稱的屬性,否則會產生一個錯誤。如果該屬性在類中的定義與在 trait 中的定義兼容(同樣的可見性和初始值)則錯誤的級別是 E_STRICT,否則是一個致命錯誤。   沖突的例子     <?php trait PropertiesTrait {     public $same = true;     public $different = false; }   class PropertiesExample {     use PropertiesTrait;     public $same = true; // Strict Standards     public $different = true; // 致命錯誤 } ?>   Use的不同 不同use的例子   <?php namespace Foo\Bar; use Foo\Test;  // means \Foo\Test - the initial \ is optional ?>   <?php namespace Foo\Bar; class SomeClass {     use Foo\Test;   // means \Foo\Bar\Foo\Test } ?>   第一個use是用於 namespace 的 use Foo\Test,找到的是 \Foo\Test,第二個 use 是使用一個trait,找到的是\Foo\Bar\Foo\Test。   __CLASS__和__TRAIT__ __CLASS__ 返回 use trait 的 class name,__TRAIT__返回 trait name         <?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   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方法 雖然不很明顯,但是如果Trait的方法可以被定義為在普通類的靜態方法,就可以被調用   實例如下   <?php  trait Foo {      function bar() {          return 'baz';      }  }    echo Foo::bar(),"\\n"; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved