OOP In Depth
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.
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.
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.
Create 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.
Create 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.
Chapter 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