前回の続き。
interfaceのinstanceofで引数判定、なんてよくやることですが、instanceof演算子はtraitには反応しません。
http://tanakahisateru.hatenablog.jp/entry/20110704/1309781929
> そりゃまあ当然で、PHP5.4のトレイトは、使用者側でアドホックにメソッド名の置き換えすらできてしまうので、「必ず特定のメソッドに応答することを保証する」インターフェースとしては使えないです。
実は元のメソッド名でも反応します。
asは単にエイリアスを作るだけなので、元のメソッド自体は残っているのです。
参考リンク先にも普通に
> Test class will now have "hello" and "helloA" methods
って書かれています。
従ってトレイトを「必ず特定のメソッドに応答することを保証する」インターフェースとして使用することは可能……と思いきや実はできません。
B::hoge as private;ってするとCall to private methodになっちゃうんですよね。
なんてこった。
ということで先方のサイトはこう読み直すのがよいでしょう。
> そりゃまあ当然で、PHP5.4のトレイトは、使用者側でアドホックに可視性の変更すらできてしまうので、「必ず特定のメソッドに応答することを保証する」インターフェースとしては使えないです。
まあ、せっかくなのでtraitをインターフェースとして使ってみます。
特にトレイト名を文字列で与えているあたりが微妙だ。
トレイト名はクラス名のようには扱うことができず、use節以外で使用するとUse of undefined constantのNoticeになってしまうようです。
こんな面倒なことをせず素直にmethod_exists($d, 'hoge')でいいや、と思ったのは秘密。
PHPにはこういう横紙破りな関数が揃ってるのが良くも悪くもナイスですね。
interfaceのinstanceofで引数判定、なんてよくやることですが、instanceof演算子はtraitには反応しません。
<?php
// 基底クラス
class A{}
// trait
trait B{
public function hoge(){
print('B::hoge/'.__CLASS__.'/'.__METHOD__);
}
}
trait C{
public function hoge(){
print('C::hoge/'.__CLASS__.'/'.__METHOD__);
}
}
// Aを継承したクラス
class D extends A{
// トレイトB,Cを使用
use B, C{
// B::hogeを優先
B::hoge insteadof C;
// B::hogeをfoo()に改名
B::hoge as foo;
// C::hogeをbar()に改名
C::hoge as bar;
}
}
$d = new D();
$d->foo(); // B:hoge/D/B::hoge
$d->bar(); // C:hoge/D/C::hoge
$d->hoge(); // B:hoge/D/B::hoge 元のメソッド名でも反応する
$d instanceof A; // true
$d instanceof C; // false
http://tanakahisateru.hatenablog.jp/entry/20110704/1309781929
> そりゃまあ当然で、PHP5.4のトレイトは、使用者側でアドホックにメソッド名の置き換えすらできてしまうので、「必ず特定のメソッドに応答することを保証する」インターフェースとしては使えないです。
実は元のメソッド名でも反応します。
asは単にエイリアスを作るだけなので、元のメソッド自体は残っているのです。
参考リンク先にも普通に
> Test class will now have "hello" and "helloA" methods
って書かれています。
従ってトレイトを「必ず特定のメソッドに応答することを保証する」インターフェースとして使用することは可能……と思いきや実はできません。
B::hoge as private;ってするとCall to private methodになっちゃうんですよね。
なんてこった。
ということで先方のサイトはこう読み直すのがよいでしょう。
> そりゃまあ当然で、PHP5.4のトレイトは、使用者側でアドホックに可視性の変更すらできてしまうので、「必ず特定のメソッドに応答することを保証する」インターフェースとしては使えないです。
まあ、せっかくなのでtraitをインターフェースとして使ってみます。
<?php
/**
* @param Object インスタンス
* @param String トレイト名
* @return boolean instanceof
*/
function trait_instanceof($trait, $className){
$class = new ReflectionClass($trait);
$traits = $class->getTraitNames();
return in_array($className, $traits, true);
}
$is = trait_instanceof($d, 'B');
微妙だ。特にトレイト名を文字列で与えているあたりが微妙だ。
トレイト名はクラス名のようには扱うことができず、use節以外で使用するとUse of undefined constantのNoticeになってしまうようです。
こんな面倒なことをせず素直にmethod_exists($d, 'hoge')でいいや、と思ったのは秘密。
PHPにはこういう横紙破りな関数が揃ってるのが良くも悪くもナイスですね。
PR