56

How can I deal with traits with methods of same name?

trait FooTrait {
 public function fooMethod() {
 return 'foo method';
 }
 public function getRow() {
 return 'foo row';
 }
}
trait TooTrait {
 public function tooMethod() {
 return 'too method';
 }
 public function getRow() {
 return 'too row';
 }
}
class Boo
{
 use FooTrait;
 use TooTrait;
 public function booMethod() {
 return $this->fooMethod();
 }
}

error,

Fatal error: Trait method getRow has not been applied, because there are collisions with other trait methods on Boo in...

What should I do about it?

And also, with two same method names, how can I get the method from trait FooTrait?

$a = new Boo;
var_dump($a->getRow()); // Fatal error: Call to undefined method Boo::getRow() in... 

Edit:

class Boo
{
 use FooTrait, TooTrait {
 FooTrait::getRow insteadof TooTrait;
 }
 public function booMethod() {
 return $this->fooMethod();
 }
}

what if I want to get the method getRow from TooTrait via Boo as well? Is it possible?

asked Jul 31, 2014 at 16:38

3 Answers 3

111

PHP Documentation about conflicts:

If two Traits insert a method with the same name, a fatal error is produced, if the conflict is not explicitly resolved.

To resolve naming conflicts between Traits used in the same class, the insteadof operator needs to be used to chose exactly one of the conflicting methods.

Since this only allows one to exclude methods, the as operator can be used to allow the inclusion of one of the conflicting methods under another name.

Example #5 Conflict Resolution

In this example, Talker uses the traits A and B. Since A and B have conflicting methods, it defines to use the variant of smallTalk from trait B, and the variant of bigTalk from trait A.

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

<?php
trait A {
 public function smallTalk() {
 echo 'a';
 }
 public function bigTalk() {
 echo 'A';
 }
}
trait B {
 public function smallTalk() {
 echo 'b';
 }
 public function bigTalk() {
 echo 'B';
 }
}
class Talker {
 use A, B {
 B::smallTalk insteadof A;
 A::bigTalk insteadof B;
 }
}
class Aliased_Talker {
 use A, B {
 B::smallTalk insteadof A;
 A::bigTalk insteadof B;
 B::bigTalk as talk;
 }
}

So in your case it could be

class Boo {
 use FooTrait, TooTrait {
 FooTrait::getRow insteadof TooTrait;
 }
 public function booMethod() {
 return $this->fooMethod();
 }
}

(it works even if you do separate use, but i think it's more clear)

Or use the as to declare an alias.

Andrew
20.4k13 gold badges111 silver badges122 bronze badges
answered Jul 31, 2014 at 16:48
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer! can I ask - what if I want to get the method getRow from TooTrait via Boo as well? Is it possible?
declare an alias. TooTrait::getRow as getRowOfToo; try
Also cracked it like this. In my opinion, the current behaviour is not the expected behaviour. I also expected, that an "as" is passed on to the using class.
Note that, surprisingly, you do NOT get a fatal error when a method in the class conflicts with an identically-named method in a trait that is used in that class, even though the trait's method is unreachable.
4

yes this is possible you can use something like this (answer for edited content) :

class Boo {
 use FooTrait, TooTrait {
 FooTrait::getRow as getFooRow;
 TooTrait::getRow as getTooRow;
 }
 public function getRow(... $arguments)
 {
 return [ 'foo' => $this->getFooRow(... $arguments), 'too' => $this->getTooRow(... $arguments) ];
 }
 public function booMethod(... $arguments)
 {
 return $this->getFooRow(... $arguments);
 }
}
answered Sep 25, 2019 at 7:44

1 Comment

Is this tested code?
1

With the accepted answer, you can cover every possible need but if your situation is simple as mine, you can just make a trait who uses your other trait which cause collasion.

trait FooTrait {
 // ...
 public function fooMethod() {
 return 'foo method';
 }
 // ...
}
trait MyFooTrait {
 use FooTrait;
 public function fooMethod() {
 return 'my foo method';
 }
}
class Boo
{
 use MyFooTrait;
}

In my situation FooTrait comes from a vendor PHP package and I want to use it with enhanced methods in several classes of my own app.

answered Apr 8, 2023 at 15:46

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.