## 概述
traits是PHP5.4新進入的特性,其目的就是解決PHP的類不能多繼承的問題。**Traits不是類!不能被實例化。**可以理解為一組能被不同的類都能調用到的方法集合。只需要在類中使用關鍵詞use引入即可,可引入多個Traits,用','隔開。
## 簡單使用
```php
trait myTrait{
public $traitPublic = 'public';
protected $traitProtected = 'protected';
function traitMethod1()
{
echo __METHOD__,PHP_EOL;
}
function traitMethod2()
{
echo __METHOD__,PHP_EOL;
}
}
class myClass{
use myTrait;
}
$obj = new myClass();
$obj->traitMethod1();
$obj->traitMethod2();
// ↓↓ 只能調用public的屬性和方法; protected以及private只供在traits內部自己調用;
echo $obj->traitPublic;
```
## 優先級問題
Trait會覆蓋繼承的方法,當前類會覆蓋Trait方法。即 繼承的方法 < Traits方法 < 當前類方法,
```php
trait A{
public $var1 = 'test';
public function test()
{
echo 'A::test()';
}
public function test1()
{
echo 'A::test1()';
}
}
class B{
public function test()
{
echo 'B::test()';
}
public function test1()
{
echo 'B::test1()';
}
}
class C extends B{
use A;
public function test()
{
echo 'c::test()';
}
}
$c = new C();
$c->test(); //c::test() Traits方法 < 當前類方法
$c->test1(); //A::test1() 繼承的方法 < Traits方法
```
## 多個Trait沖突問題
1. 如果兩個 trait 都插入了一個同名的方法,如果沒有明確解決沖突將會產生一個致命錯誤。
2. 為了解決多個 trait 在同一個類中的命名沖突,需要使用 insteadof 操作符來明確指定使用沖突方法中的哪一個。
3. 可用as操作符將其中一個沖突方法另起名;
```php
trait A{
public function test()
{
echo 'A::test()';
}
}
trait B{
public function test()
{
echo 'B::test()';
}
}
class C{
use A , B {
B::test insteadof A; //明確B替代A
B::test as t; //或者另起一個名字
}
}
$c = new C();
$c->test(); //B::test()
$c->t(); //B::test() 可以用as另起名
```
## as可用來修改方法訪問控制
```php
trait HelloWorld{
public function sayHello()
{
echo 'Hello World!';
}
}
// 修改 sayHello 的訪問控制
class A{
use HelloWorld {
sayHello as protected;
}
}
// 給方法一個改變了訪問控制的別名
// 原版 sayHello 的訪問控制則沒有發生變化
class B{
use HelloWorld {
sayHello as private myPrivateHello;
}
}
$a = new A();
$a->sayHello(); //Fatal error: Call to protected method A::sayHello() from context ''; 改變了sayHello的訪問規則;
$b = new B();
$b->sayHello(); //Hello World!
```
## 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;
// 必須要實現trait里面的抽象方法,否則Fatal error: Class MyHelloWorld contains 1 abstract method and must therefore be declared abstract or implement the remaining methods
public function getWorld()
{
return $this->world;
}
public function setWorld($val)
{
$this->world = $val;
}
}
$obj = new MyHelloWorld();
echo $obj->setWorld();
```
## Trait中靜態成員
Traits 可以被靜態成員靜態方法定義,不可以直接定義靜態變量,但靜態變量可被trait方法引用.
```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
$o->inc(); // echo 2;
$p = new C2();
$p->inc(); // echo 1
# 靜態方法
trait StaticExample {
public static function doSomething() {
echo 'Doing something';
}
}
class Example {
use StaticExample;
}
Example::doSomething(); // Doing something
```
## Trait中屬性
```php
trait PropertiesTrait{
public $x = 1;
}
class PropertiesExample{
use PropertiesTrait;
}
$example = new PropertiesExample;
echo $example->x; // 1
```
如果 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; // 致命錯誤
}
```
參考鏈接:
http://www.php.net/manual/zh/language.oop5.traits.php
- 現代化PHP特性
- php7常用特性整理
- 反射機制Reflection
- 依賴注入與服務容器
- 抽象類與接口
- 類多繼承的替代方案Traits
- 類的延遲綁定(后期綁定)
- 生成器語法
- 匿名函數和閉包
- 匿名類
- 理解php的output buffer
- 斷言ASSERT
- 魔術方法小結
- Zend Opcache字節碼緩存
- 內置的http服務器
- SPL標準庫
- 【SPL標準庫專題(1)】SPL簡介
- 【SPL標準庫專題(2)】Iterator
- 【SPL標準庫專題(3)】Classes
- 【SPL標準庫專題(4)】Exceptions
- 【SPL標準庫專題(5)】Datastructures:SplDoublyLinkedList
- 【SPL標準庫專題(6)】Datastructures:SplStack & SplQueue
- 【SPL標準庫專題(7)】Datastructures:SplPriorityQueue
- 【SPL標準庫專題(8)】Datastructures:SplHeap & SplMaxHeap & SplMinHeap
- 【SPL標準庫專題(9)】Datastructures:SplFixedArray
- 【SPL標準庫專題(10)】Datastructures:SplObjectStorage
- PHPcomposer使用手札[ing]
- PHP中的多態
- 通過命名空間實現自動加載的框架雛形
- 日期與金額
- PHPstorm使用攻略
- 筆記本