Trait Conflict Resolution
Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 53 of 91.
When two traits define methods with the same name, PHP throws a fatal error. You must explicitly tell PHP how to handle this conflict using the insteadof and as operators.
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");
Output:
File: Error occurred
DB: Error occurredThe insteadof operator chooses which trait's method to use when there's a conflict. In this example, FileLogger::log wins and becomes the default log() method. The as operator creates an alias, letting you access the other trait's method under a different name.
You can also use as to change a method's visibility:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
This makes sayHello() private within the Person class, even though it's public in the trait. Conflict resolution gives you fine-grained control over how trait methods integrate into your classes.
Challenge
EasyLet's build a notification system where different channels can send messages, but we need to resolve conflicts when multiple traits provide the same method name.
You'll organize your code across four files:
EmailNotifier.php— Create a trait calledEmailNotifierwith a methodnotify(string $message)that returns"Email: [message]".SmsNotifier.php— Create a trait calledSmsNotifierwith a methodnotify(string $message)that returns"SMS: [message]".AlertService.php— Create anAlertServiceclass that uses both traits. Since both traits have anotify()method, you'll need to resolve this conflict:- Use
EmailNotifier::notifyas the defaultnotify()method - Create an alias
notifyBySmsfor theSmsNotifier::notifymethod
notifyAll(string $message)that calls both notification methods and returns them combined on separate lines.- Use
main.php— Include all the necessary files and create anAlertServiceinstance. You'll receive one input: a message string. Print three lines:- The result of calling
notify()with the message - The result of calling
notifyBySms()with the message - The result of calling
notifyAll()with the message
- The result of calling
This demonstrates how insteadof resolves which trait's method wins when there's a naming conflict, while as lets you keep access to the other trait's method under a different name.
Cheat sheet
When multiple traits define methods with the same name, PHP requires explicit conflict resolution using insteadof and as operators.
The insteadof operator selects which trait's method to use as the default:
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred"); // File: Error occurred
$app->logToDatabase("Error occurred"); // DB: Error occurred
The as operator creates an alias for a trait method, allowing access under a different name.
You can also use as to change method visibility:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
Try it yourself
<?php
require_once 'AlertService.php';
// Read input
$message = trim(fgets(STDIN));
// TODO: Create an AlertService instance
// TODO: Print the result of calling notify() with the message
// TODO: Print the result of calling notifyBySms() with the message
// TODO: Print the result of calling notifyAll() with the message
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern