Oop Patterns

By the end of this lesson you'll wield PHP's full object toolkit — interfaces, abstract classes, traits, inheritance, polymorphism, final and late static binding — and see how they snap together into the Strategy and Factory patterns that real applications are built from.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Interfaces — a Contract to Sign

An interface is a promise. It lists method names and their signatures but no actual code — it describes what a class must be able to do, never how . A class then writes implements SomeInterface to "sign the contract", and PHP forces it to define every listed method or the file won't run. The power is that a function can type-hint the interface and then accept any class that signs it — your code depends on the capability, not on one specific class.

Notice describe(Shape $s) never mentions Circle or Rectangle . It only knows it received "something that is a Shape", so you can add a Triangle tomorrow and describe() keeps working untouched.

2️⃣ Abstract Classes — Half-Built Blueprints

An abstract class sits between an interface and a normal class. Like an interface it can declare abstract methods — empty methods that every child must fill in. But unlike an interface it can also hold real, shared code, properties, and a constructor. You can never write new Animal() directly; an abstract class exists only to be extends -ed. Use it when several closely related classes share behaviour but each needs to fill in one or two specifics.

Each child wrote speak() just once, yet both got the entire introduce() method and the constructor for free. That's the trade an interface can't make: shared code lives in one place.

3️⃣ Traits — Horizontal Reuse

PHP allows single inheritance only: a class can extends exactly one parent. So how do unrelated classes share the same code — say logging, used by both an Article and an Invoice ? A trait is a bundle of methods you use inside any class, as if they were pasted in. A class can pull in many traits. If two traits define a method with the same name , PHP stops with an error until you resolve it: insteadof picks the winner and as keeps the loser under a new name.

4️⃣ Inheritance, Polymorphism, final & Late Static Binding

When a class extends another, it inherits everything and may override a method by redefining it with a matching signature . Inside an override, parent::method() calls the version you just replaced so you can extend rather than discard it. Polymorphism ("many forms") is the pay-off: loop over a mixed list of objects, call the same method on each, and every object runs its own version. final locks a class or method so it can't be extended or overridden. And late static binding — the static keyword — makes new static() in a parent build the child that was actually called.

The single foreach loop is polymorphism in one line: three different classes, one method call, three different results. And CardPayment::of(99.99) proves late static binding — the of() code lives in the parent yet returned a CardPayment .

5️⃣ A Brief Look at Patterns: Strategy & Factory

Design patterns are just named, repeatable ways to combine the features above. The Strategy pattern defines an interface for an algorithm, then lets you swap interchangeable implementations at runtime — the client holds "a strategy" without caring which. The Factory pattern hides object creation behind a method, so callers ask for a type by name instead of writing new for a specific class. You've already used the bricks; here they are assembled.

Now you try. The script below is almost complete — fill in each ___ using the 👉 hint, then run it and check it against the Output panel.

One more. This time you'll extend an abstract class and fill in its one hole.

📋 Quick Reference — interface vs abstract vs trait

No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments. This is the write-run-check loop you'll use on every real class.

Practice quiz

Which keyword does a class use to sign an interface contract?

  • extends
  • use
  • implements
  • abstract

Answer: implements. A class writes 'implements SomeInterface' and must then define every method the interface lists.

What is the key difference between an interface and an abstract class?

  • An interface is signatures only; an abstract class can hold real shared code
  • An abstract class has no methods
  • An interface can be instantiated
  • They are identical

Answer: An interface is signatures only; an abstract class can hold real shared code. An interface is a pure contract; an abstract class can also carry shared code, properties, and a constructor.

How many classes can a single class extend in PHP?

  • Two
  • Unlimited
  • Zero
  • One

Answer: One. PHP allows single inheritance only — a class extends exactly one parent. Traits give horizontal reuse.

What happens if you try new Animal() on an abstract class Animal?

  • It creates an empty Animal
  • An error — abstract classes cannot be instantiated
  • It returns null
  • It calls the first child class

Answer: An error — abstract classes cannot be instantiated. Abstract classes are blueprints; you must instantiate a concrete child that extends them.

Inside an override, how do you call the version you just replaced?

  • parent::method()
  • self::method()
  • this::method()
  • super.method()

Answer: parent::method(). parent::method() reaches the overridden parent version so you can extend rather than discard it.

What is late static binding — what does new static() build?

  • Always an instance of the parent class
  • A static array
  • An instance of the class that was actually called at runtime
  • A new interface

Answer: An instance of the class that was actually called at runtime. 'static' resolves to the called class, so new static() in a parent factory returns the child's type.

Why use 'static' instead of 'self' in a base-class factory method?

  • self is faster
  • self is locked to where it is written; static follows the called class
  • static only works on properties
  • There is no difference

Answer: self is locked to where it is written; static follows the called class. new self() always builds the parent; new static() builds whichever child invoked the method.

What does the final keyword do?

  • Marks a class as abstract
  • Makes a method static
  • Allows multiple inheritance
  • Prevents a class from being extended or a method from being overridden

Answer: Prevents a class from being extended or a method from being overridden. final locks behaviour: a final class can't be extended and a final method can't be overridden.

If two traits define a save() method, how do you pick which wins?

  • FileStore::save overrides CloudStore;
  • FileStore::save insteadof CloudStore;
  • use FileStore not CloudStore;
  • PHP picks automatically

Answer: FileStore::save insteadof CloudStore;. insteadof picks the winner; 'CloudStore::save as saveToCloud;' keeps the loser under a new name.

What does the Strategy pattern let you do?

  • Create objects without using new
  • Lock a class from extension
  • Swap interchangeable algorithm implementations behind one interface at runtime
  • Merge two traits

Answer: Swap interchangeable algorithm implementations behind one interface at runtime. Strategy defines an interface for an algorithm and lets the client hold any implementation without caring which.