[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(自动加载)