TiMESPLiNTER
TiMESPLiNTER

Reputation: 5889

Multiple traits uses same base trait at the same time

Okay say the following straits are given:

trait Base
{
    public function doSomething()
    {
        // Do fancy stuff needed in other traits
    }
}

trait A
{
    use Base;

    public function foo()
    {
        // Do something
    }
}


trait B
{
    use Base;

    public function bar()
    {
        // Do something else
    }
}

and I like to implement a class now which uses both traits A and B:

class MyClass
{
    use A, B;
}

PHP tells me it can't redefine function doSomething(). What's the reason PHP is not able to detect that A and B share one and the same trait and don't copy it twice into MyClass (is it a bug or a feature preventing me from writing unclean code)?

Is there a better solution for my problem then this workaround with which I ended up:

trait Base
{
    public function doSomething()
    {
        // Do fancy stuff needed in other traits
    }
}

trait A
{
    abstract function doSomething();

    public function foo()
    {
        // Do something
    }
}


trait B
{
    abstract function doSomething();

    public function bar()
    {
        // Do something else
    }
}

And then my class:

class MyClass
{
    use Base, A, B;
}

Upvotes: 11

Views: 9094

Answers (2)

Lucas Bustamante
Lucas Bustamante

Reputation: 17188

This has been fixed in PHP 7.3:

trait A
{
    public function a(){}
}

trait B
{
    use A;
}

trait C
{
    use A;
}

class D
{
    use B, C;
}

Results:

PHP 7.3+ Fine
PHP ^5|^7.2: Fatal error: Trait method a has not been applied, because there are collisions with other trait methods on D in /in/Z5GTo on line 18

Props to @Grzegorz that posted the link to the PHP bug, to an answer, but got deleted by vote. I tried to re-open it but couldn't.

Upvotes: 4

arbogastes
arbogastes

Reputation: 1328

You can resolve this conflict with "insteadof" like this:

class MyClass
{
    use A, B {
        A::doSomething insteadof B;
    }
} 

EDIT For more traits resolving conflicts can look like this:

class MyClass
{
    use A, B, C, D {
        A::doSomething insteadof B, C, D;
    }
}  

Upvotes: 15

Related Questions