Сценарий:
trait A { function calc($v) { return $v+1; } } class MyClass { use A; function calc($v) { $v++; return A::calc($v); } } print (new MyClass())->calc(2); // should print 4
Этот код не работает, и я не могу найти способ вызвать функцию признака, как будто она была унаследована. Я попытался вызвать self::calc($v)
, static::calc($v)
, parent::calc($v)
, A::calc($v)
и следующее:
trait A { function calc($v) { return $v+1; } } class MyClass { use A { calc as traitcalc; } function calc($v) { $v++; return traitcalc($v); } }
Ничего не работает.
Есть ли способ заставить его работать, или я должен полностью переопределить функцию признака, которая намного сложнее, чем эта 🙂
Твой последний был почти там:
trait A { function calc($v) { return $v+1; } } class MyClass { use A { calc as protected traitcalc; } function calc($v) { $v++; return $this->traitcalc($v); } }
Эта черта не класс. Вы не можете напрямую обращаться к своим членам. Это просто автоматическая копия и вставка …
Если класс реализует метод напрямую, он не будет использовать версию признаков. Возможно, вы думаете о том, что вы думаете:
trait A { function calc($v) { return $v+1; } } class MyClass { function calc($v) { return $v+2; } } class MyChildClass extends MyClass{ } class MyTraitChildClass extends MyClass{ use A; } print (new MyChildClass())->calc(2); // will print 4 print (new MyTraitChildClass())->calc(2); // will print 3
Поскольку дочерние классы не реализуют метод напрямую, они сначала будут использовать свойство признака, если иначе использовать родительский класс.
Если вы хотите, черта может использовать метод в родительском классе (если вы знаете, что метод будет там), например
trait A { function calc($v) { return parent::calc($v*3); } } // .... other code from above print (new MyTraitChildClass())->calc(2); // will print 8 (2*3 + 2)
Вы также можете указать способы переопределения, но по-прежнему обращаться к методу признаков следующим образом:
trait A { function trait_calc($v) { return $v*3; } } class MyClass { function calc($v) { return $v+2; } } class MyTraitChildClass extends MyClass{ use A { A::trait_calc as calc; } } class MySecondTraitChildClass extends MyClass{ use A { A::trait_calc as calc; } public function calc($v) { return $this->trait_calc($v)+.5; } } print (new MyTraitChildClass())->calc(2); // will print 6 echo "\n"; print (new MySecondTraitChildClass())->calc(2); // will print 6.5
Вы можете видеть, что это работает на http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5
Альтернативный подход, если он заинтересован, – с дополнительным промежуточным классом, чтобы использовать обычный способ OOO. Это упрощает использование с parent :: methodname
trait A { function calc($v) { return $v+1; } } // an intermediate class that just uses the trait class IntClass { use A; } // an extended class from IntClass class MyClass extends IntClass { function calc($v) { $v++; return parent::calc($v); } }
Используя другой признак:
trait ATrait { function calc($v) { return $v+1; } } class A { use ATrait; } trait BTrait { function calc($v) { $v++; return parent::calc($v); } } class B extends A { use BTrait; } print (new B())->calc(2); // should print 4