Ankaj Gupta
October 02, 2020

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.

Key Takeaways

  • Polymorphism enables a single interface to represent multiple concrete behaviors.
  • Use inheritance, interfaces, and magic methods to achieve polymorphism in PHP.
  • Favor interface-driven design and keep method contracts consistent to maintain substitutability.
  • Reserve magic methods for advanced use cases, and pair them with error handling and tests.
oops php programming

Join the discussion

Comments

0 comments

No comments yet — be the first to share your thoughts.

Related Posts