OOP In Depth: Inheritance, Interfaces, Abstract Classes, and Traits
Chapter 1 built single, standalone classes. Real applications usually have several related classes that share common structure — a Dog and a Cat are both Animals, for instance. This chapter covers four distinct tools PHP offers for expressing that kind of relationship, each suited to a slightly different situation.
Inheritance — extends
Dog extends Animal means every Dog automatically gets everything Animal defines — eat() didn't need to be rewritten at all. Re-defining makeSound() inside Dog is called overriding — PHP always uses the most specific version available for whichever object the method is called on.
parent:: — Calling the Parent's Version Anyway
An override doesn't have to fully replace the parent's behaviour — parent::methodName() calls the original version too, useful for "do the normal thing, plus something extra."
Abstract Classes — A Blueprint That Can't Be Used Directly
An abstract class can mix concrete methods (describe(), fully written) with abstract ones (getArea(), no body — just a required signature). It cannot be instantiated directly with new; it exists purely to be extended, guaranteeing every subclass implements the methods marked abstract.
Interfaces — A Pure Contract, No Implementation At All
An interface defines method signatures only — no bodies at all, not even partial ones. A class implements an interface to promise it provides those methods. The real power: printPrice() doesn't care whether it receives a Book, a Car, or anything else — only that it implements Sellable, so it definitely has a getPrice() method.
| Tool | What it gives you |
|---|---|
| extends | A class inherits from one parent class (single inheritance only) |
| abstract class | Partial blueprint — some methods written, some left required-but-empty |
| interface | Pure contract — method signatures only, a class can implement many |
| trait | Reusable method code, mixed into a class — covered next |
extends. But implements Sellable, Comparable, Loggable (comma-separated) is entirely valid, since interfaces are just promises about method signatures, not actual shared code to merge.
Traits — Sharing Actual Method Code, Without Inheritance
Order and User have no inheritance relationship to each other at all — they're unrelated classes that both happen to need logging behaviour. A trait solves exactly this: actual, reusable method code that gets copied into any class using use TraitName;, sidestepping the "only one parent class" limit of extends.
extends. Want to guarantee a method exists, with no implementation to share → interface. Want a partial blueprint mixing some shared code with some required-but-unwritten methods → abstract class. Need to share actual method code across otherwise-unrelated classes → trait.
Coding Challenges
Create an Animal class with a constructor setting $name, and a method makeSound() that echoes a generic message. Create Cat and Cow classes that extend it and override makeSound() with their own sound. Create one of each and call makeSound() on both.
📄 View solutionCreate an abstract class Employee with a constructor setting $name, an abstract method calculatePay(): float, and a concrete method describe() that echoes the name and calculated pay together. Create two subclasses, SalariedEmployee and HourlyEmployee, each implementing calculatePay() differently.
📄 View solutionCreate a trait Greetable with a method sayHello() that echoes "Hello from " followed by a $name property. Use this trait in two unrelated classes, Robot and Alien (neither extending the other, or any common parent), each with their own $name set via a constructor. Call sayHello() on one instance of each.
📄 View solutionChapter 2 Quick Reference
- extends — single inheritance; subclass gets everything the parent has, can override methods
- parent::method() — calls the parent's original version from inside an override
- abstract class — partial blueprint; cannot be instantiated; abstract methods MUST be implemented by subclasses
- interface — pure method signatures, no bodies; a class can implement several
- trait — reusable method code, mixed into otherwise unrelated classes via "use"
- Decision guide: is-a → extends; guaranteed method, no shared code → interface; partial shared blueprint → abstract class; shared code across unrelated classes → trait
- Next chapter: error handling — exceptions, try/catch/finally, custom exceptions