Resolving method conflicts
Learn to resolve conflicts in traits with the same method name using insteadof and as.
Conflict on the same method name
If two traits contain a method with the same name and you use both, PHP throws a fatal error. You resolve the conflict with insteadof: you choose which trait's method wins.
class Report {
use XmlReporter, CsvReporter {
XmlReporter::format insteadof CsvReporter;
}
}Here format() calls XmlReporter's method; CsvReporter's method is suppressed.
Renaming with as (alias)
Sometimes you don't want the conflicting method to disappear; you want it reachable under a different name. For this you use as: it gives the method an alias.
use XmlReporter, CsvReporter {
XmlReporter::format insteadof CsvReporter;
CsvReporter::format as asCsv;
}Now $r->format() returns XML, and $r->asCsv() returns CSV. Both methods are reachable.
Exercise Resolve the XmlReporter and CsvReporter conflict
Define an XmlReporter trait: its public function format(): string method does return "XML";. Define a CsvReporter trait: its public function format(): string method does return "CSV";. Then a Report class uses both and, in a use block, writes XmlReporter::format insteadof CsvReporter; and CsvReporter::format as asCsv;. With $r = new Report() call echo $r->format() . "\n" and echo $r->asCsv() . "\n".
Show example solution
:format insteadof CsvReporter; CsvReporter::format as asCsv; } }.
Example solution:
<?php
// Resolve the XmlReporter and CsvReporter conflict with insteadof and as
trait XmlReporter {
public function format(): string {
return "XML";
}
}
trait CsvReporter {
public function format(): string {
return "CSV";
}
}
class Report {
use XmlReporter, CsvReporter {
XmlReporter::format insteadof CsvReporter;
CsvReporter::format as asCsv;
}
}
$r = new Report();
echo $r->format() . "\n";
echo $r->asCsv() . "\n";
Test yourself
-
Which keyword resolves a trait method conflict?
- override
- parent::
- insteadof
- final
Show answer
insteadof — Correct. insteadof picks which of two conflicting trait methods wins.
-
Resolve the conflict with insteadof
trait CacheA { public function store() { return "A"; } } trait CacheB { public function store() { return "B"; } } class Repo { use CacheA, CacheB { CacheA::store ____ CacheB; } } $r = new Repo(); echo $r->store() . "\n";Show answer
trait CacheA { public function store() { return "A"; } } trait CacheB { public function store() { return "B"; } } class Repo { use CacheA, CacheB { CacheA::store insteadof CacheB; } } $r = new Repo(); echo $r->store() . "\n"; -
After CacheA::store insteadof CacheB;, what does $r->store() return?
- A
- B
- Fatal error
- null
Show answer
A — Correct. insteadof makes CacheA win, so $r->store() returns A.