[TOC]
* * * * *
## 1 Trait的意義
**將不同類中相同代碼組織到同一個trait中,避免代碼重復編寫。**
以tp5的model擴展實現為例
thinkphp/library/trait/model下的Adv.php
這個**trait中定義模型擴展中通用方法**。
由在/thinkphp/library/think/model/目錄下的
Adv.php,Mongo.php中**分別引入**
**避免了**在Adv.php與Mongo.php中**編寫相同的代碼**
trait在**PHP5.4中引入**。
與類相似,使用細粒度和一致的方式組織功能代碼
**不能通過自身實例化,需要在類中使用use引入使用**
與多繼承與混入類(Mixin)的功能相似
為傳統類的單繼承增加了**代碼組合的另一種方法**
* * * * *
## 2 Trait的簡單使用
~~~
<?php
trait ezcReflectionReturnInfo {
function getReturnType () { /*1*/ }
function getReturnDescription () { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo ;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo ;
/* ... */
}
?>
~~~
使用**trait關鍵字**定義了**重復代碼內容**
在需要引入trait的類中使用**關鍵字use**引入了對應的trait代碼
為兩個類都添加了getReturnType(),getReturnDescription()方法
## 3 Trait的內部組織
>[info] 屬性
trait中可以定義類中需要的屬性。
~~~
<?php
trait PropertiesTrait {
public $x = 1 ;
}
class PropertiesExample {
use PropertiesTrait ;
}
$example = new PropertiesExample ;
$example -> x ;
?>
~~~
類PropertiesExample使用了trait的$x屬性。
**類中不能定義trait已定義的屬性**,否則產生錯誤
如果類中屬性與trait的屬性具有相同的可見性和初始值,錯誤級別是E_SRTICT,否則是指明錯誤
~~~
<?php
trait PropertiesTrait {
public $same = true ;
public $different = false ;
}
class PropertiesExample {
use PropertiesTrait ;
public $same = true ; // Strict Standards
public $different = true ; // 致命錯誤
}
?>
~~~
>[info] 方法
通常使用trait**定義類中需要重復使用的方法代碼**。如簡單使用中的例子
>[info] 修飾符
trait中的屬性和方法可以使用
**public,static,abstract等修飾符修飾,**
設置屬性和方法的**訪問控制**。
靜態變量的使用
~~~
<?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 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 ;
}
}
?>
~~~
>[info] 組合
在trait中可以使用use引入其他的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 ();
?>
~~~
## 4 Trait的高級使用
>[info] 覆蓋優先級
類的成員覆蓋引入的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 ();
?>
~~~
從基類繼承的成員被插入的 SayWorld Trait 中的 MyHelloWorld 方法所覆蓋。
其行為 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 ();
?>
~~~
>[info] 引入多個trait
通過逗號在use聲明中可以引入多個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 ();
?>
~~~
>[info] 多個trait沖突
如果兩個 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 的別名。
>[info] as修改訪問控制
使用 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 ; }
}
?>
~~~
## 5 tp5中的trait
使用T()或者Loader::import()可以導入對應trait
~~~
thinkphp\library\think\Controller.php:
namespace think;
T('controller/Jump');
class Controller
{
use \traits\controller\Jump;
// 視圖類實例
protected $view = null;
...
}
~~~
~~~
thinkphp\library\think\model\Adv.php:
namespace think\model;
\think\Loader::import('model/Adv', TRAIT_PATH, EXT);
\think\Loader::import('model/Transaction', TRAIT_PATH, EXT);
class Adv extends \think\Model
{
use \traits\model\Adv;
use \traits\model\Transaction;
}
~~~
~~~
thinkphp\library\think\model\Mongo.php:
namespace think\model;
use think\Lang;
use think\Loader;
\think\Loader::import('modle/Adv', TRAIT_PATH, EXT);
/**
* MongoModel模型類
* 實現了ODM和ActiveRecords模式
*/
class Mongo extends \think\Model
{
use \traits\model\Adv;
...
}
~~~
- 更新記錄
- 概述
- 文件索引
- 函數索引
- 章節格式
- 框架流程
- 前:章節說明
- 主:(index.php)入口
- 主:(start.php)框架引導
- 主:(App.php)應用啟動
- 主:(App.php)應用調度
- C:(Controller.php)應用控制器
- M:(Model.php)數據模型
- V:(View.php)視圖對象
- 附:(App.php)應用啟動
- 附:(base.php)全局變量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自動加載器
- 附:(Build.php)自動生成
- 附:(Hook.php)監聽回調
- 附:(Route.php)全局路由
- 附:(Response.php)數據輸出
- 附:(Log.php)日志記錄
- 附:(Exception.php)異常處理
- 框架工具
- 另:(helper.php)輔助函數
- 另:(Cache.php)數據緩存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制臺
- 另:(Debug.php)開發調試
- 另:(Error.php)錯誤處理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加載器實例化
- 另:(Input.php)數據輸入
- 另:(Lang.php)語言包管理
- 另:(ORM.php)ORM基類
- 另:(Process.php)進程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驅動
- D:(\config)配置解析
- D:(\controller)控制器擴展
- D:(\model)模型擴展
- D:(\db)數據庫驅動
- D:(\view)模板解析
- D:(\template)模板標簽庫
- D:(\session)session驅動
- D:(\cache)緩存驅動
- D:(\console)控制臺
- D:(\process)進程擴展
- T:(\traits)Trait目錄
- D:(\exception)異常實現
- D:(\log)日志驅動
- 使用范例
- 服務器與框架的安裝
- 控制器操作
- 數據模型操作
- 視圖渲染控制
- MVC開發初探
- 模塊開發
- 入口文件定義全局變量
- 運行模式開發
- 框架配置
- 自動生成應用
- 事件與插件注冊
- 路由規則注冊
- 輸出控制
- 多種應用組織
- 綜合應用
- tp框架整合后臺auto架構快速開發
- 基礎原理
- php默認全局變量
- php的魔術方法
- php命名空間
- php的自動加載
- php的composer
- php的反射
- php的trait機制
- php設計模式
- php的系統時區
- php的異常錯誤
- php的輸出控制
- php的正則表達式
- php的閉包函數
- php的會話控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整體結構
- 心:配置詳解
- 心:加載器詳解
- 心:輸入輸出詳解
- 心:url路由詳解
- 心:模板詳解
- 心:模型詳解
- 心:日志詳解
- 心:緩存詳解
- 心:控制臺詳解
- 框架更新
- 4.20(驗證類,助手函數)
- 4.27(新模型Model功能)
- 5.4(新數據庫驅動)
- 7.28(自動加載)