Polymorphism in php with example
PHP Fundamentals
Understanding Polymorphism in PHP
Polymorphism lets you interact with different objects through a common interface and still get behavior tailored to the object you are working with. In PHP, polymorphism sits at the heart of writing testable, extensible, and reusable object-oriented code.
Definition: Polymorphism describes the ability of different classes to respond to the same method call in different, class-specific ways.
The term comes from the Greek words poly (many) and morph (form). A single message—such as render() or process()—can trigger different logic depending on the object that receives it.
Why it matters
Keeps code flexible, reduces duplicate branching logic, and makes maintenance easier.
Where you use it
Framework controllers, service layers, strategy patterns, payment gateways, and more.
Polymorphism Techniques in PHP
Modern PHP uses polymorphism primarily through interfaces, inheritance, and magic methods. The table below highlights the main approaches.
| Technique | Best for | Key Benefit |
|---|---|---|
| Method overriding | Extending base classes | Replace or refine default behavior |
| Interfaces & abstract classes | Formal contracts for implementations | Guarantees consistent API surface |
Magic methods (__call, __callStatic) |
Dynamic or proxy objects | Intercept unknown method calls |
Method Overriding (Runtime Polymorphism)
In PHP, overriding happens when a child class redefines a method inherited from a parent class. When you invoke the method on the child, PHP executes the child’s version.
<?php
abstract class Notification
{
abstract public function send(string $message): void;
}
class EmailNotification extends Notification
{
public function send(string $message): void
{
echo "๐ง Sending email: {$message}\n";
}
}
class SmsNotification extends Notification
{
public function send(string $message): void
{
echo "๐ฑ Sending SMS: {$message}\n";
}
}
function notifyUser(Notification $channel): void
{
$channel->send('Your order has shipped!');
}
notifyUser(new EmailNotification());
notifyUser(new SmsNotification());
What happens: The notifyUser() function does not care which concrete class it receives. Each object answers the send() call with behavior of its own.
Interfaces and Polymorphism
Interfaces in PHP define a contract. Any class that implements the interface guarantees it will provide the required methods, making them interchangeable at runtime.
interface PaymentGateway
{
public function charge(int $amount): bool;
}
class StripeGateway implements PaymentGateway
{
public function charge(int $amount): bool
{
// call Stripe API...
return true;
}
}
class OfflineGateway implements PaymentGateway
{
public function charge(int $amount): bool
{
// record cash payment...
return true;
}
}
function checkout(PaymentGateway $gateway): void
{
if ($gateway->charge(1999)) {
echo "Payment complete";
}
}
checkout(new StripeGateway()); // easily swap with OfflineGateway
Tip: Depend on interfaces rather than concrete classes. This keeps code loosely coupled and easy to extend.
Dynamic Polymorphism with Magic Methods
PHP’s __call() and __callStatic() intercept method calls that do not exist. This is useful for proxy objects, adapters, or builders.
class LazyConfig
{
private array $data = [];
public function __call(string $name, array $arguments)
{
if (str_starts_with($name, 'set')) {
$key = lcfirst(substr($name, 3));
$this->data[$key] = $arguments[0] ?? null;
return $this;
}
if (str_starts_with($name, 'get')) {
$key = lcfirst(substr($name, 3));
return $this->data[$key] ?? null;
}
throw new BadMethodCallException("Unknown method {$name}");
}
}
$config = (new LazyConfig())
->setHost('localhost')
->setPort(3306);
echo $config->getHost(); // localhost
Caution: Magic methods are powerful but can hide bugs. Always validate method names and keep good tests.
Best Practices for Polymorphic PHP Code
Do
- Design around interfaces and dependency injection
- Keep method signatures consistent when overriding
- Document expectations using PHPDoc and type hints
- Test behavior through the shared interface
Avoid
- Mixing business logic with type checks (
instanceof) - Overusing magic methods for basic domain logic
- Breaking Liskov Substitution Principle when overriding
- Returning different types than the interface promises
Common Pitfalls
Duplicate method names: PHP does not support compile-time overloading like Java. Declaring two methods with the same name in a class causes a fatal error.
Missing return types: If a parent declares a return type, child classes must honor it or use compatible covariant types (PHP 7.4+).
Leaky abstractions: When subclasses expose details not promised by the interface, polymorphism breaks down.