Polymorphism
Learn how polymorphism lets different classes respond to the same method call in their own way.
Introduction
Picture a media player that can play an `Mp3`, a `Podcast`, or a `Video`. Each one plays completely differently under the hood, yet you would like to write one simple loop that calls `play()` on whatever item comes next, without checking what type it is first. That is exactly the problem polymorphism solves.
The word literally means "many forms." In object-oriented PHP, it describes calling the same method name on different objects and getting behavior appropriate to each object's own class.
- What polymorphism means: same method name, different behavior per class.
- How method overriding is the main mechanism behind it.
- How to loop over different objects and call the same method on each.
- How type declarations combined with inheritance make this safe.
What Is Polymorphism?
Polymorphism means that calling the exact same method name on objects of different classes runs different code, appropriate to each class, without the calling code needing to know which class it is dealing with.
- Same method name, e.g. speak() or area().
- Different classes provide different implementations of that method.
- Calling code just says $object->speak() — it does not need an if/else chain checking the object's type.
Method Overriding as the Mechanism
In PHP, polymorphism is achieved primarily through method overriding, which you saw in the previous lesson: subclasses of a shared parent (or implementers of a shared interface) each define their own version of the same method name.
<?php
abstract class Animal
{
protected string $name;
public function __construct(string $name)
{
$this->name = $name;
}
abstract public function speak(): string;
}
class Dog extends Animal
{
public function speak(): string
{
return "{$this->name} says Woof!";
}
}
class Cat extends Animal
{
public function speak(): string
{
return "{$this->name} says Meow!";
}
}
class Cow extends Animal
{
public function speak(): string
{
return "{$this->name} says Moo!";
}
}Each subclass provides its own `speak()`. The method name never changes, but each class's version behaves differently — that difference in behavior, tied to a shared method name, is polymorphism.
Worked Example: Shared Method, Different Behavior
The real payoff of polymorphism shows up when you loop over a collection of different objects and call the same method on each, without any type-checking logic at all.
<?php
// Using the Animal, Dog, Cat, Cow classes from above
$animals = [
new Dog("Rex"),
new Cat("Whiskers"),
new Cow("Bessie"),
];
foreach ($animals as $animal) {
echo $animal->speak() . "\n";
}Rex says Woof!
Whiskers says Meow!
Bessie says Moo!The `foreach` loop treats every element identically — it only knows it has an `Animal` and calls `speak()` on it. There is no `if ($animal instanceof Dog) { ... } elseif ($animal instanceof Cat) { ... }` chain anywhere. Each object automatically runs its own version of `speak()`. This is what makes polymorphic code easy to extend: adding a new `Bird` class that also extends `Animal` and defines its own `speak()` requires no changes at all to the loop above.
Type Declarations Make It Safe
Polymorphism relies on every object in the collection genuinely being able to respond to the shared method. PHP's type declarations, combined with inheritance (or interfaces, covered next lesson), let you enforce this safely.
<?php
function announce(Animal $animal): void
{
echo $animal->speak() . "\n";
}
announce(new Dog("Rex"));
announce(new Cat("Whiskers"));
// announce("not an animal"); // Fatal error: Argument must be of type AnimalRex says Woof!
Whiskers says Meow!Because the `announce()` function's parameter is typed as `Animal`, PHP guarantees at call time that whatever is passed in — a `Dog`, a `Cat`, a `Cow`, or any future subclass — really does have a `speak()` method available. That guarantee is what lets polymorphic code stay both flexible and safe.
Common Mistakes
- Writing long if/elseif chains that check an object's type before deciding what to do — this defeats the purpose of polymorphism.
- Forgetting to override a method in a subclass, causing it to silently fall back to the parent's behavior when a distinct one was intended.
- Giving overriding methods in different subclasses different names or signatures, breaking the shared interface the loop depends on.
- Skipping type declarations on parameters, allowing objects that do not actually support the expected method to be passed in.
Best Practices
- Design a common parent class or interface first, then let each subclass override the shared method with its own behavior.
- Prefer polymorphic method calls over type-checking conditionals whenever you find yourself branching on an object's class.
- Use type declarations on parameters and properties so PHP enforces that objects genuinely share the expected method.
- Keep overridden method signatures consistent across subclasses so calling code never needs special cases.
Frequently Asked Questions
Is polymorphism the same thing as method overriding?
Method overriding is the main mechanism that enables polymorphism in PHP, but polymorphism is the broader concept: the same method call producing behavior appropriate to each object's actual class.
Do I need an abstract class for polymorphism to work?
No, though it is common. Interfaces (covered next) also let unrelated classes share a method signature, which is another common route to polymorphism.
What if two subclasses need genuinely different parameters for the same method?
That breaks the shared calling convention polymorphism relies on. Keep overridden method signatures consistent, and use different method names for behavior that truly needs different inputs.
Can polymorphism reduce the need for switch statements?
Yes. A common refactor is replacing a switch statement that branches on type with polymorphic method calls on a shared parent or interface.
Key Takeaways
- Polymorphism means the same method name behaves differently depending on the object's actual class.
- Method overriding is the primary mechanism PHP uses to achieve polymorphism.
- You can loop over a mix of related objects and call the same method on each without checking types.
- Type declarations combined with inheritance or interfaces make polymorphic code safe and predictable.
Summary
Polymorphism lets you write simpler, more extensible code by calling one shared method name across many different object types, each responding in its own way. Combined with type declarations, it lets PHP enforce that every object really does support the behavior your code expects.
- You can explain what polymorphism means in your own words.
- You understand method overriding as its main mechanism.
- You can loop over related objects and call a shared method on each.
- You know why type declarations help make polymorphism safe.