Traits and Conflicts

Traits, Conflict Resolution and Abstract Trait Methods

A trait (PHP 5.4) is a bundle of methods and properties that PHP copies into every class that says use TraitName;. It is not a type and cannot be instantiated. A class may use several traits, and a trait may use others. When two traits bring the same method name, insteadof picks one and as keeps the other under an alias, optionally with new visibility. An abstract trait method demands something of the host class; PHP 8.0 enforces its signature.

Two traits with a clashing log() method, resolved in the classPHP
<?php
trait Logs {
  public function log(string $msg): string { return static::class . " log: $msg"; }
  public function describe(): string { return 'describe() from trait Logs'; }
}
trait Audits {
  abstract protected function actor(): string;             // the host class must supply it
  public function log(string $msg): string { return "audit by {$this->actor()}: $msg"; }
}
class Model { public function describe(): string { return 'describe() from Model'; } }
final class Order extends Model {
  use Logs, Audits {
    Audits::log insteadof Logs;                             // pick one log()
    Logs::log as protected plainLog;                        // keep the other, renamed
  }
  protected function actor(): string { return 'admin'; }
  public function save(): string { return $this->plainLog('saved'); }
}
$o = new Order();
echo $o->log('refund issued'), "\n", $o->save(), "\n", $o->describe(), "\n";
Output
audit by admin: refund issued
Order log: saved
describe() from trait Logs

The last line shows precedence: a class's own method beats a trait method, which beats an inherited one. Without insteadof, PHP stops with Trait method Audits::log has not been applied as Order::log, because of collision with Logs::log. In a trait, static::class and __CLASS__ name the using class.