Home » Php » Why method renaming does not work in PHP traits?

Why method renaming does not work in PHP traits?

Posted by: admin July 12, 2020 Leave a comment

Questions:

I use PHP 7.1.0.

Let’s say we have a trait, we use it inside a class and rename the imported method:

trait T
{
    public function A() {
        echo ".";
    }
}

class C
{
    use T {
        A as B;
    }
}

$c = new C();
$c->B();
$c->A(); // Why does it work?

Why does PHP still allow me to use old method name (A in this case)?

It’s really a pain because in more complex examples you cannot rely on method renaming – and thus you can unexpectedly receive “incompatible declarations” error:

class BaseSrc
{
}

trait BaseTrait
{
    public function init(BaseSrc $baseSrc)
    {
        echo "Init Base";
    }
}

class Base
{
    use BaseTrait {
        BaseTrait::init as initBase;
    }
}

$base = new Base();
$base->initBase(new BaseSrc());
$base->init(new BaseSrc()); // WHY DOES IT WORK?????

class MainSrc extends BaseSrc
{
}

trait MainTrait
{
    use BaseTrait {
        BaseTrait::init as initBase;
    }

    public function init(MainSrc $mainSrc)
    {
        $this->initBase($mainSrc);
        echo "Init Main";
    }
}

// Warning: Declaration of MainTrait::init(MainSrc $mainSrc) should be compatible with Base::init(BaseSrc $baseSrc)
class Main extends Base
{
    use MainTrait;
}

I think, this code should work. Since I renamed init() into initBase() in the Base class AND did the same renaming when using BaseTrait inside MainTrait, I expect that this method (BaseTrait::init()) will not conflict with MainTrait::init(). In fact, PHP says that I have incompatible declarations. The reason behind it is that renaming init as initBase does not work – method init is still there, in my Base class!

Is there any way how to solve this problem without renaming BaseTrait::init() into something like BaseTrait::initBase() from the very beginning (not just in the use statement)?

Should I consider this as a PHP bug and report it? Is there anything reasonable behind this behaviour?

How to&Answers:

As mentioned in the comments and for completeness; From the PHP manual section on Traits:

The Aliased_Talker makes use of the as operator to be able to use
B’s bigTalk implementation under an additional alias talk.

And then:

The as operator can be used to add an alias to one of the methods.
Note the as operator does not rename the method and it does not affect
any other method either.

So as adds an alias but does not replace or affect the original method in any way. This is the expected behavior.