PHP
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?
Show answer
A — Correct. insteadof makes CacheA win, so $r->store() returns A.
Next lesson: Trait vs inheritance