說明 PHP語言本身可以用insteadof和as關鍵字解決多個trait同名成員方法衝突的問題,但是貌似沒有直接解決同名成員屬性衝突的方案。 雖然屬性名衝突極少發生,但是不代表不會發生。 如果是自定義trait 可以複製舊trait文件到新trait,改新文件的成員屬性名,引用新trait。 直接 ...
說明
PHP語言本身可以用insteadof和as關鍵字解決多個trait同名成員方法衝突的問題,但是貌似沒有直接解決同名成員屬性衝突的方案。
雖然屬性名衝突極少發生,但是不代表不會發生。
如果是自定義trait
- 可以複製舊trait文件到新trait,改新文件的成員屬性名,引用新trait。
- 直接更改原trait成員屬性名,可能會影響項目。
如果就不動原trait,僅通過類怎麼解決?(例如某些trait在vendor下,極少的情況下需要同時引用多個trait,他們的屬性衝突了)
示例
如下:C類想用A Trait和B Trait的方法,但是屬性名衝突,報錯。
Fatal error: A and B define the same property ($prop) in the composition of C. However, the definition differs and is considered incompatible. Class was composed。
trait A {
public $prop = 'trait_a';
public function speakEnglish() {
echo 'English';
}
}
trait B {
public $prop = 'trait_b';
public function speakChinese() {
echo '中文';
}
}
class C {
use A,B;
}
$c = new C();
echo $c->prop;
錯誤的解決方案
PHP語言本身可以用insteadof和as關鍵字解決多個trait同名成員方法衝突的問題,但是這無法修飾成員屬性。
報錯:Fatal error: A precedence rule was defined for A::prop but this method does not exist.
class C {
use A,B {
A::prop insteadof B;
B::prop as B_prop;
}
}
$c = new C();
echo $c->prop;
正確的解決方案
- 需要一個父類參與,相當於一個中間人為衝突雙方做調解。
- 併在父類中引入任意一個trait,相當於告訴這個trait停止衝突。
- 子類繼承父類並引入另一個trait,並重新聲明屬性並賦初始值,相當於告訴另一個trait也停止衝突,而且支持你。
- 此時子類繼承了家業又化解了衝突。
- 需要註意:C類中的
public $prop = 'trait_b'
不能少,且必須等於B trait中的值,否則會報致命錯誤。
trait A {
public $prop = 'trait_a';
public function speakEnglish() {
echo 'English';
}
}
trait B {
public $prop = 'trait_b';
public function speakChinese() {
echo '中文';
}
}
class P {
use A;
}
class C extends P {
use B;
public $prop = 'trait_b';
//構造方法為非必填項
public function __construct() {
$this->prop = 'new value';
}
}
$c = new C();
echo $c->prop;
$c->speakEnglish();
$c->speakChinese();
至此,使用父類可巧妙化解PHP Trait成員屬性衝突的問題,讓不能更改的兩個trait,既不衝突,又能同時為我所用。