PHPでTraitのメソッド名をasで変更してuseして、うまいことする
PHPのTraitはuseしたクラスでTraitと同じメソッド名のメソッドを定義すると、それで上書きしてしまう。
<?php trait MyTrait { public function foo() { echo "MyTrait::foo()~~~\n"; } } class Hoge { use MyTrait; public function foo() { // 上書きしてしまう echo "Hoge::foo()======\n"; } } (new Hoge)->foo(); //=> Hoge::foo()======
Traitは継承関係に組み込まれるわけではないので、parentで呼ぶこともできない。
<?php trait MyTrait { ... } class Hoge { use MyTrait; public function foo() { parent::foo(); // parentで呼んでみる echo "Hoge::foo()======\n"; } }
PHP Fatal error: Cannot access parent:: when current class scope has no parent
こんなときは、useするときに、asで別名にして差し込めばいいみたい。
<?php trait MyTrait { ... } class Hoge { use MyTrait { foo as bar; } // Traitのfooの名前をbarにする public function foo() { $this->bar(); // barで呼ぶ echo "Hoge::foo()======\n"; } } //=> MyTrait::foo()~~~ //=> Hoge::foo()======
親クラス、子クラス、Traitの同名メソッドを全部呼ぶ
これを利用して(というか使わざるを得ない)、継承とTraitのメソッドを全部たどって呼ぶ方法。
<?php trait HogeTrait { // Traitの h() メソッド public function h() { $res = parent::h(); // ParentHoge::h()を呼ぶ echo "HogeTrait::h() dayo\n"; $res['trait'] = 'traitdayo'; return $res; } } class ParentHoge { // 親クラスの h() メソッド public function h() { echo "ParentHoge::h() dayo\n"; return ['parent' => 'parentdayo']; } } class ChildHoge extends ParentHoge { use HogeTrait { h as hh; } // 別名で上書きを防ぐ // 子クラスの h() メソッド public function h() { $res = $this->hh(); echo "ChildHoge::h() dayo\n"; return $res; } } $res = (new ChildHoge())->h(); var_dump($res); //=> ParentHoge::h() dayo //=> HogeTrait::h() dayo //=> ChildHoge::h() dayo //=> array(2) { //=> 'parent' => //=> string(10) "parentdayo" //=> 'trait' => //=> string(9) "traitdayo" //=> }
ちなみにRuby
RubyのMixinは親子関係に組み込まれるので、ModuleをincludeしたクラスでsuperでModuleのメソッドが呼べる。
module HogeModule def h res = super puts "HogeTrait::h() dayo" res[:module] = 'moduledayo' res end end class ParentHoge def h puts "ParentHoge::h() dayo" {parent: 'parentdayo'} end end class ChildHoge < ParentHoge include HogeModule def h res = super puts "ChildHoge::h() dayo" res end end h = ChildHoge.new p h.h #=> ParentHoge::h() dayo #=> HogeTrait::h() dayo #=> ChildHoge::h() dayo #=> {:parent=>"parentdayo", :module=>"moduledayo"}