How to Override Trait Function and Call It from the Overridden Function

How to override trait function and call it from the overridden function?

Your last one was almost there:

trait A {
function calc($v) {
return $v+1;
}
}

class MyClass {
use A {
calc as protected traitcalc;
}

function calc($v) {
$v++;
return $this->traitcalc($v);
}
}

The trait is not a class. You can't access its members directly. It's basically just automated copy and paste...

Why trait does not override method in class?

Read this carefully Trait documentation I recommend to try out every example and make your own modifications to be sure you understand it. There is my example, hope it helps:

<?php
class A {
public function foo() {
echo "x";
}
}

class B extends A {}

$test = new B();
$test->foo();

// result X

This is pretty clear I think, so now lets use a Trait:

<?php
class A {
public function foo() {
echo "x";
}
}

trait T {
public function foo() {
echo "y";
}
}

class B extends A {
use T;
}

$test = new B();
$test->foo();

// result y

As you can see the Trait method overwrites the base class method. And now lets create a foo method in the B class

<?php
class A {
public function foo() {
echo "x";
}
}

trait T {
public function foo() {
echo "y";
}
}

class B extends A {
use T;
public function foo() {
echo "z";
}
}

$test = new B();
$test->foo();

// result z

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.

Call own method from trait

I've got the solution from this answer.

class A extends ABase
{
use MyTrait {
configureOptions as traitConfigureOptions;
}
//...
}

and then, instead of parent::configureOptions($resolver):

$this->traitConfigureOptions($resolver);

How to call an overridden function in a method in the Parent class

I fixed this by updating the scope of the methods from private to protected.

PHP override trait method of parent class's trait

Consider the following code:

<?php    
trait AA {
function f() {
echo "I'm AA::f".PHP_EOL;
}
}
class A {
use AA;
}
trait BB {
function f() {
echo "I'm BB::f".PHP_EOL;
}
}
class B extends A {
use BB;
}
$b = new B();
$b->f();

I'm BB::f

I believe that traits work like copy-paste code. The trait code is treated like a "copy-pasted" code in the class it's used in so you can pretend that the trait is not really inherited but it's code is just part of the parent class.

programmatically identify methods that override trait methods

You could make almost sure a method overrides a trait method by comparing:

  • their file names
    (ReflectionFunctionAbstract::getFileName),
  • and their start lines (ReflectionFunctionAbstract::getStartLine)

Condition

if ($class_method->getFileName() !== $trait_method->getFileName() 
|| $class_method->getStartLine() !== $trait_method->getStartLine()) {
$methods_overridden[] = $class_method->getName();
}

(of course, they also need to have the same name)

Full function

/**
* Given a class name, retrieves the corresponding class' methods that override
* trait methods.
*
* @param string $class_name
* @return \ReflectionMethod[]
* @throws \ReflectionException
*/
function getMethodsOverriddenFromTraits(string $class_name): array
{
$class = new \ReflectionClass($class_name);

// Retrieve trait methods

$trait_methods = [];
foreach ($class->getTraits() as $trait) {
foreach ($trait->getMethods() as $trait_method) {
$trait_methods[$trait_method->getName()] = $trait_method;
}
}

// Compute class methods that override them

$methods_overridden = [];
foreach ($class->getMethods() as $class_method) {
if (array_key_exists($class_method->getName(), $trait_methods)) {
$trait_method = $trait_methods[$class_method->getName()];
if ($class_method->getFileName() !== $trait_method->getFileName()
|| $class_method->getStartLine() !== $trait_method->getStartLine()) {
$methods_overridden[] = $class_method->getName();
}
}
}

return $methods_overridden;
}

Demo here: https://3v4l.org/EcFIC



Related Topics



Leave a reply



Submit