罠ってほどでもない
例えば下のようなコードがあったとします。
<?php
trait A
{
public function hoge()
{
echo 'hoge' . PHP_EOL;
}
public function fuga()
{
echo 'fuga' . PHP_EOL;
}
}
trait B
{
public function hoge()
{
echo 'hogeB' . PHP_EOL;
}
public function fuga()
{
$this->hoge();
}
}
class C
{
use A, B {
A::hoge insteadof B;
A::fuga insteadof B;
B::hoge as hoge2;
B::fuga as fuga2;
}
public function main()
{
$this->hoge();
$this->fuga();
$this->hoge2();
$this->fuga2();
}
}
$instance = new C();
$instance->main();
要するに、同じメソッド名を持つトレイトをクラスに取り込んだ上で、Aのメソッドを優先し、Bのメソッドにはエイリアスをつける、というようなコードです。
さて、上記のコードを実行すると何が出力されるでしょう?
答え
% php test.php
hoge
fuga
hogeB
hoge
どういうことだってばよ…
つまり、C::main()
で $this->fuga2()
を呼んだとき、B::fuga2()
の中身は「B::hoge()
を実行せよ」という意味ではなく「C::hoge()
(つまり A::hoge()
)を実行せよ」と解釈されるため、B::hoge()
が呼ばれることはない、ということなんですねー。
応用
以下の様な感じでインターフェイスとトレイトを使えばこんなことも。
<?php
interface A
{
public function hoge();
public function fuga();
public function piyo();
}
trait B
{
public function hoge()
{
return 'hoge';
}
}
trait C
{
public function fuga()
{
echo $this->hoge() . PHP_EOL;
echo $this->piyo() . PHP_EOL;
}
}
class D implements A
{
use B;
use C;
public function main()
{
$this->fuga();
}
public function piyo()
{
return 'piyo';
}
}
$instance = new D();
$instance->main();
% php test.php
hoge
piyo