Question
Given this PHP trait and class, how can MyClass override the trait's calc() method while still calling the original implementation supplied by the trait?
trait A
{
public function calc($v)
{
return $v + 1;
}
}
class MyClass
{
use A;
public function calc($v)
{
$v++;
return A::calc($v);
}
}
print (new MyClass())->calc(2); // Expected output: 4
Calls such as self::calc($v), static::calc($v), parent::calc($v), and A::calc($v) do not call the original trait method. Is there a way to reuse the trait implementation instead of completely rewriting a more complex method?
Short Answer
PHP traits are copied into the classes that use them; they are not parent classes that can be called with parent::. To override a trait method and still reuse it, give the trait method an alias during use, then call that alias through $this.
Concept
A PHP trait is a mechanism for sharing methods among multiple classes. When a class uses a trait, PHP composes the trait's methods into that class.
This is different from class inheritance:
- A child class can call an inherited parent method with
parent::method(). - A trait does not become a parent object or parent class.
- Therefore,
A::calc()is not a valid way to invoke the implementation of traitAfrom an object.
When a class defines a method with the same name as a trait method, the class method takes precedence. This lets you customize trait behavior, but it also hides the trait method under its original name.
PHP solves this with trait adaptations. You can create an alias for the trait method in the use statement. The class can then define its own calc() method and call the aliased trait method, such as $this->traitCalc($v).
This is useful when a trait contains reusable default behavior, while one class needs to add validation, logging, normalization, or a small adjustment before or after that behavior.
Mental Model
Think of a trait as a recipe copied into a class's cookbook.
When MyClass uses trait A, the calc() recipe is copied into MyClass. If MyClass writes its own recipe also named calc(), that new recipe is the one people use.
An alias is like saving the copied recipe under a second label:
- Public class recipe:
calc() - Saved original recipe:
traitCalc()
Your custom calc() recipe can now perform extra work and then call the saved original recipe with $this->traitCalc(...).
Syntax and Examples
Use a trait adaptation block to alias the trait method:
use TraitName {
methodName as aliasName;
}
Then call the alias as an instance method:
$this->aliasName($value);
Here is a complete example:
<?php
trait A
{
public function calc($v)
{
return $v + 1;
}
}
class MyClass
{
use A {
calc as protected traitCalc;
}
public function calc($v)
{
$v++;
return ->();
}
}
= ();
->();
Step by Step Execution
Consider this code:
$result = (new MyClass())->calc(2);
Execution proceeds as follows:
new MyClass()creates aMyClassobject.- PHP calls
MyClass::calc(2), because a class method takes precedence over a trait method with the same name. - Inside
MyClass::calc(),$vstarts as2. $v++changes$vfrom2to3.$this->traitCalc(3)calls the alias forA::calc()that was imported from the trait.- The trait implementation returns
3 + 1, which is4. MyClass::calc()returns4.
Real World Use Cases
Trait method aliases are useful when a shared implementation is mostly correct but one class needs a small variation.
- Logging: Add a log entry before delegating to the trait's save, send, or calculate method.
- Input normalization: Trim text, convert units, or standardize a date before invoking shared behavior.
- Validation: Check class-specific rules before performing the trait's default action.
- Metrics: Measure execution time around the original trait method.
- Decorating output: Call the trait method first, then format or enrich its returned result.
- Framework extensions: A trait may implement common behavior for models, controllers, commands, or services, while a particular class adds a narrow customization.
Real Codebase Usage
In real codebases, prefer a descriptive alias that explains why the method exists:
use CalculatesPrice {
calculate as protected calculateBasePrice;
}
Then make the public override easy to read:
public function calculate(float $amount): float
{
if ($amount < 0) {
throw new InvalidArgumentException('Amount cannot be negative.');
}
$basePrice = $this->calculateBasePrice($amount);
return $basePrice + $this->handlingFee;
}
Common project patterns include:
- Guard clauses: Reject invalid input before calling the aliased trait method.
- Before/after hooks: Do setup first, call the base implementation, then process its result.
- Visibility control: Keep the alias
protectedor so callers only see the intended public method.
Common Mistakes
Calling the trait as though it were a parent class
return A::calc($v); // Incorrect
A trait is not a parent class and is not used as an object instance in this situation. Alias the trait method and call it on the current object instead.
Calling the overriding method recursively
public function calc($v)
{
return $this->calc($v); // Incorrect: calls itself forever
}
This causes infinite recursion until PHP throws an error. Call the alias instead:
return $this->traitCalc($v);
Using self::calc() or static::calc()
return self::calc($v);
::();
Comparisons
| Feature | Trait method alias | parent::method() | Method override only |
|---|---|---|---|
| Main purpose | Preserve access to a trait implementation under another name | Call an inherited parent-class implementation | Replace behavior completely |
| Requires a parent class | No | Yes | No |
| Typical call | $this->traitCalc() | parent::calc() | $this->calc() is usually recursion |
| Can change alias visibility | Yes | No | Not applicable |
| Best for | Extending a trait method without copying it | Extending inherited behavior |
Cheat Sheet
trait ExampleTrait
{
public function work($value)
{
return $value;
}
}
class Example
{
use ExampleTrait {
work as protected traitWork;
}
public function work($value)
{
// Extra behavior here.
return $this->traitWork($value);
}
}
- Traits are composed into a class; they are not parent classes.
- A class method overrides a trait method with the same name.
- Create an alias with
use TraitName { method as alias; }. - Call the alias with
$this->alias(). - Use
protectedfor an internal alias in most cases. - Do not use
parent::unless a real parent class defines the method. - Do not use inside an override unless recursion is intended.
FAQ
Can I call a PHP trait method directly with TraitName::method()?
No. Traits are not instantiated or called like ordinary classes in this use case. Import the trait method into a class and call it through that class instance.
How do I call the original trait method after overriding it?
Alias the method in the trait use statement, then call the alias with $this->aliasName().
Why does parent::calc() not call the trait method?
parent:: refers only to the class extended by the current class. A trait is not a parent class.
Does aliasing remove the original trait method?
No. An alias adds another name for the trait method. If the class defines the original name, the class method takes precedence for that name.
Should a trait method alias be public or protected?
Usually protected. The alias is commonly an internal implementation detail, while the overriding method is the public API.
Can I change the visibility of a trait method with an alias?
Yes. For example, calc as protected traitCalc; creates a protected alias.
Can I use this with static trait methods?
Yes, traits can contain static methods, but the call and design should match static-method rules. For ordinary object behavior, instance methods and $this->alias() are clearer.
Mini Project
Description
Build a small order calculator that uses a trait for a default subtotal calculation. A special order class will override the calculation to add a handling fee while still reusing the trait's original logic.
Goal
Create an ExpressOrder class whose overridden method adds a handling fee and then delegates the subtotal calculation to a trait alias.
Requirements
- Create a trait with a public
calculateTotal(float $subtotal): floatmethod. - Make the trait apply a 10% tax to the subtotal.
- Create an
ExpressOrderclass that uses the trait and aliases its method. - Override
calculateTotal()to add a5.00handling fee before applying tax. - Keep the aliased trait method non-public.
- Print the total for a subtotal of
100.00.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.