PHP 實(shí)現(xiàn)代碼復(fù)用的一個(gè)方法 traits新特性
來(lái)源:易賢網(wǎng) 閱讀:983 次 日期:2015-03-13 10:01:30
溫馨提示:易賢網(wǎng)小編為您整理了“PHP 實(shí)現(xiàn)代碼復(fù)用的一個(gè)方法 traits新特性”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了PHP 實(shí)現(xiàn)代碼復(fù)用的一個(gè)方法,traits的新特性的相關(guān)資料,需要的朋友可以參考下

在閱讀yii2源碼的時(shí)候接觸到了trait,就學(xué)習(xí)了一下,寫下博客記錄一下。

自 PHP 5.4.0 起,PHP 實(shí)現(xiàn)了代碼復(fù)用的一個(gè)方法,稱為 traits。

Traits 是一種為類似 PHP 的單繼承語(yǔ)言而準(zhǔn)備的代碼復(fù)用機(jī)制。Trait 為了減少單繼承語(yǔ)言的限制,使開發(fā)人員能夠自由地在不同層次結(jié)構(gòu)內(nèi)獨(dú)立的類中復(fù)用方法集。Traits 和類組合的語(yǔ)義是定義了一種方式來(lái)減少?gòu)?fù)雜性,避免傳統(tǒng)多繼承和混入類(Mixin)相關(guān)的典型問題。

Trait 和一個(gè)類相似,但僅僅旨在用細(xì)粒度和一致的方式來(lái)組合功能。Trait 不能通過它自身來(lái)實(shí)例化。它為傳統(tǒng)繼承增加了水平特性的組合;也就是說(shuō),應(yīng)用類的成員不需要繼承。

Trait 示例

代碼如下:

<?php

trait ezcReflectionReturnInfo {

function getReturnType() { /*1*/ }

function getReturnDescription() { /*2*/ }

}

class ezcReflectionMethod extends ReflectionMethod {

use ezcReflectionReturnInfo;

/* ... */

}

class ezcReflectionFunction extends ReflectionFunction {

use ezcReflectionReturnInfo;

/* ... */

}

?>

優(yōu)先級(jí)

從基類繼承的成員被 trait 插入的成員所覆蓋。優(yōu)先順序是來(lái)自當(dāng)前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。

優(yōu)先順序示例

代碼如下:

<?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();

?>

以上例程會(huì)輸出:Hello World!

從基類繼承的成員被插入的 SayWorld Trait 中的 sayHello 方法所覆蓋。其行為 MyHelloWorld 類中定義的方法一致。優(yōu)先順序是當(dāng)前類中的方法會(huì)覆蓋 trait 方法,而 trait 方法又覆蓋了基類中的方法。

另一個(gè)優(yōu)先級(jí)順序的例子

代碼如下:

<?php

trait HelloWorld {

public function sayHello() {

echo 'Hello World!';

}

}

class TheWorldIsNotEnough {

use HelloWorld;

public function sayHello() {

echo 'Hello Universe!';

}

}

$o = new TheWorldIsNotEnough();

$o->sayHello();

?>

以上例程會(huì)輸出:Hello Universe!

多個(gè) trait

通過逗號(hào)分隔,在 use 聲明列出多個(gè) trait,可以都插入到一個(gè)類中。

多個(gè) 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();

?>

以上例程會(huì)輸出:Hello World!

沖突的解決

如果兩個(gè) trait 都插入了一個(gè)同名的方法,如果沒有明確解決沖突將會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤。

為了解決多個(gè) trait 在同一個(gè)類中的命名沖突,需要使用 insteadof 操作符來(lái)明確指定使用沖突方法中的哪一個(gè)。

以上方式僅允許排除掉其它方法,as 操作符可以將其中一個(gè)沖突的方法以另一個(gè)名稱來(lái)引入。

沖突解決的例子

代碼如下:

<?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 操作符來(lái)定義了 talk 來(lái)作為 B 的 bigTalk 的別名。

修改方法的訪問控制

使用 as 語(yǔ)法還可以用來(lái)調(diào)整方法的訪問控制。

修改方法的訪問控制的例子

代碼如下:

<?php

trait HelloWorld {

public function sayHello() {

echo 'Hello World!';

}

}

// 修改 sayHello 的訪問控制

class MyClass1 {

use HelloWorld { sayHello as protected; }

}

// 給方法一個(gè)改變了訪問控制的別名

// 原版 sayHello 的訪問控制則沒有發(fā)生變化

class MyClass2 {

use HelloWorld { sayHello as private myPrivateHello; }

}

?>

從 trait 來(lái)組成 trait

正如類能夠使用 trait 一樣,其它 trait 也能夠使用 trait。在 trait 定義時(shí)通過使用一個(gè)或多個(gè) trait,它能夠組合其它 trait 中的部分或全部成員。

從 trait 來(lái)組成 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();

?>

以上例程會(huì)輸出:Hello World!

Trait 的抽象成員

為了對(duì)使用的類施加強(qiáng)制要求,trait 支持抽象方法的使用。

表示通過抽象方法來(lái)進(jìn)行強(qiáng)制要求的例子

代碼如下:

<?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 的靜態(tài)成員

Traits 可以被靜態(tài)成員靜態(tài)方法定義。

靜態(tài)變量的例子

代碼如下:

<?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

?>

靜態(tài)方法的例子

代碼如下:

<?php

trait StaticExample {

public static function doSomething() {

return 'Doing something';

}

}

class Example {

use StaticExample;

}

Example::doSomething();

?>

靜態(tài)變量和靜態(tài)方法的例子

代碼如下:

<?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 定義了一個(gè)屬性,那類將不能定義同樣名稱的屬性,否則會(huì)產(chǎn)生一個(gè)錯(cuò)誤。如果該屬性在類中的定義與在 trait 中的定義兼容(同樣的可見性和初始值)則錯(cuò)誤的級(jí)別是 E_STRICT,否則是一個(gè)致命錯(cuò)誤。

沖突的例子

代碼如下:

<?php

trait PropertiesTrait {

public $same = true;

public $different = false;

}

class PropertiesExample {

use PropertiesTrait;

public $same = true; // Strict Standards

public $different = true; // 致命錯(cuò)誤

}

?>

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

}

?>

第一個(gè)use是用于 namespace 的 use Foo\Test,找到的是 \Foo\Test,第二個(gè) use 是使用一個(gè)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單例

實(shí)例如下

代碼如下:

<?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;

調(diào)用trait方法

雖然不很明顯,但是如果Trait的方法可以被定義為在普通類的靜態(tài)方法,就可以被調(diào)用

實(shí)例如下

代碼如下:

<?php

trait Foo {

function bar() {

return 'baz';

}

}

echo Foo::bar(),"\\n";

?>

小伙伴們對(duì)于traits的新特性是否熟悉了呢,希望本文能對(duì)大家有所幫助。

更多信息請(qǐng)查看IT技術(shù)專欄

更多信息請(qǐng)查看網(wǎng)絡(luò)編程
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國(guó)考·省考課程試聽報(bào)名

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)