PHP 是單繼承語言,Traits(特徵)自 PHP 5.4 引入,解決了類別無法同時繼承多個父類的限制。本文詳細說明 Traits 的語法、優先順序、衝突解決、存取控制修改、靜態成員與抽象方法等進階用法,並附完整代碼範例。
<?php
trait Drive {
public $carName = 'trait';
public function driving() { echo "driving {$this->carName}\n"; }
}
class Person { public function eat() { echo "eat\n"; } }
class Student extends Person {
use Drive;
public function study() { echo "study\n"; }
}
$student = new Student();
$student->study(); // study
$student->eat(); // eat
$student->driving(); // driving trait
?>
trait Drive { public function hello() { echo "hello drive\n"; } public function driving() { echo "driving from drive\n"; } }
class Person { public function hello() { echo "hello person\n"; } public function driving() { echo "driving from person\n"; } }
class Student extends Person {
use Drive;
public function hello() { echo "hello student\n"; }
}
$student = new Student();
$student->hello(); // hello student (類別覆蓋)
$student->driving(); // driving from drive (Trait 覆蓋父類別)
?>
insteadof 與 astrait Trait1 { public function hello() { echo "Trait1::hello\n"; } public function hi() { echo "Trait1::hi\n"; } }
trait Trait2 { public function hello() { echo "Trait2::hello\n"; } public function hi() { echo "Trait2::hi\n"; } }
class Class1 {
use Trait1, Trait2 {
Trait2::hello insteadof Trait1;
Trait1::hi insteadof Trait2;
}
}
class Class2 {
use Trait1, Trait2 {
Trait2::hello insteadof Trait1;
Trait1::hi insteadof Trait2;
Trait2::hi as hei;
Trait1::hello as hehe;
}
}
$obj1 = new Class1(); $obj1->hello(); $obj1->hi(); // Trait2::hello, Trait1::hi
$obj2 = new Class2(); $obj2->hello(); $obj2->hi(); $obj2->hei(); $obj2->hehe();
// Trait2::hello, Trait1::hi, Trait2::hi, Trait1::hello
?>
trait Hello { public function hello() { echo "hello,trait\n"; } }
class Class1 { use Hello { hello as protected; } }
class Class2 { use Hello { Hello::hello as private hi; } }
$o1 = new Class1(); $o1->hello(); // Fatal error: protected
$o2 = new Class2(); $o2->hello(); // 正常 (public)
$o2->hi(); // Fatal error: private
?>
trait Hello { public function sayHello() { echo "Hello\n"; } }
trait World {
use Hello;
public function sayWorld() { echo "World\n"; }
abstract public function getWorld();
public function inc() { static $c = 0; echo ++$c . "\n"; }
public static function doSomething() { echo "Doing something\n"; }
}
class HelloWorld { use World; public function getWorld() { return 'get World'; } }
$obj = new HelloWorld();
$obj->sayHello(); $obj->sayWorld(); echo $obj->getWorld() . "\n";
HelloWorld::doSomething(); $obj->inc(); $obj->inc();
/* 輸出:
Hello
World
get World
Doing something
1
2
*/
as 關鍵字可別名或改變可見性善用 Traits 能讓類別設計更靈活、符合單一職責原則。