3.2Object-oriented programming (classes, inheritance, interfaces)
The essentials in 30 seconds
- The class is a blueprint, the object an instance: properties (data) + methods (behaviours), new to create, $this for the current object, __construct to initialize.
- Encapsulation protects state: private properties + validating getters/setters — the object guarantees its own consistency.
- Inheritance, interfaces and traits structure: extends to specialize, interface to contract, trait to share without inheritance.
Running case — Riad tidies his spaghetti code into objects
Riad, web developer in Constantine, manages users and orders with arrays and scattered functions: an invalid email slipped in anywhere breaks sending. He models a Utilisateur class (private properties, validating setters, initializing constructor), an Admin class that extends Utilisateur, and a Notifiable interface both implement. Invalid data is rejected at the source, the code reads like the business.
This same case returns in the lesson, the diagram, the script and the 48h challenge.
1. Classes, objects and encapsulation
OOP organises code around objects grouping data and behaviours. The class is the blueprint: properties (a user has a name, an email) and methods (they can log in). You create objects with $user = new User(), the __construct() constructor initializes at creation, and $this refers to the current object ($this->nom).
Encapsulation controls access via visibility: public (everywhere), private (class only), protected (class + descendants). Properties are made private and accessed through validating getters/setters: no invalid email can be set directly. The object protects its state — a key robustness principle Riad applies to every entity.
2. Inheritance, polymorphism, interfaces and traits
Inheritance (class Admin extends User) reuses and specializes: Admin gets everything from User, adds or overrides methods. Polymorphism lets different classes answer the same method each in its own way — ideal for generic code. Abstraction hides complexity behind simple interfaces.
Interfaces are contracts: they declare methods a class MUST implement, without saying how — you program “to a contract”, you decouple (essential for testing). Traits share methods between classes without inheritance (PHP allows only one extends). Riad remembers the hierarchy: contract first (interface), sharing next (trait), specialization last (extends).
The $this that mistook itself for others
Private first: an object keeps its business to itself.
🔎 Concrete example — Encapsulated class and inheritance
Riad models a user validating its email, then an admin.
nom = $nom;
$this->setEmail($email);
}
public function setEmail(string $email): void {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email.');
}
$this->email = $email;
}
public function getEmail(): string { return $this->email; }
}
class Admin extends Utilisateur {
public function peutAcceder(string $ressource): bool { return true; }
}
Reading: initializing constructor, private-backed validating setter, specializing inheritance.
Lesson: an invalid email is rejected at the source — the object guarantees its consistency.
Section vocabulary
- OOP / class / object
- Paradigm organising code into objects (data + behaviours); the class is the blueprint, the object an instance (new); $this = current, __construct = initialization.
Simple example: new Utilisateur('Riad', 'riad@fictitious-example.test').
What it is not: scattered functions and variables with no blueprint.
Reflex: model each business entity as a class.
- Encapsulation / visibility
- Grouping and controlling access: public (everywhere), private (class only), protected (class + descendants); private + getters/setters to protect state.
Simple example: Riad's setEmail refusing the invalid.
What it is not: public properties modifiable any which way.
Reflex: private properties by default.
- Inheritance
- class Admin extends User: reuses the parent's members, adds or overrides; an “is a kind of” relationship.
Simple example: Admin inherits from Utilisateur and overrides peutAcceder().
What it is not: copy-pasted methods between classes.
Reflex: inherit to specialize, not to copy.
- Polymorphism / abstraction
- Same method, different behaviours per class; hiding complexity behind simple interfaces.
Simple example: Each role answers peutAcceder() in its own way.
What it is not: a giant switch on the object type.
Reflex: call the method, let the object decide.
- Interfaces / traits
- Interface: contract of methods to implement (decouple, test). Trait: horizontal sharing of methods without inheritance.
Simple example: Notifiable implemented by Utilisateur and Order.
What it is not: depending everywhere on a concrete class.
Reflex: depend on interfaces, share via traits.
In practice — Thinking and programming in objects
- Create a class (e.g. User) with properties (name, email) and methods; instantiate with `new`, initialize via __construct, use $this.
- Apply ENCAPSULATION: private properties, access via validating getters/setters; type the properties.
- Create a class that INHERITS (extends) and OVERRIDES a method; observe reuse and specialization.
- Define an INTERFACE (contract) and a class implementing it; explore a trait to share methods.
Ready-to-say script — presenting your object modelling (30 s)
“Users are modelled as a class: private properties, initializing constructor, setters validating the email. Admin inherits from Utilisateur and overrides its rights, and both implement the Notifiable interface. Invalid data is rejected at the source.”
Say in review; show the setter throwing the exception.
Copy-paste template — encapsulated class + interface
nom = $nom;
$this->setEmail($email);
}
public function setEmail(string $email): void {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email.');
}
$this->email = $email;
}
public function getEmail(): string { return $this->email; }
}
class Admin extends Utilisateur {
public function peutAcceder(string $ressource): bool { return true; }
}
Independent
One encapsulated Client class is enough to make generated quotes reliable.
SME in Constantine
Riad models linked clients, orders and admins, each validating its state.
Product team
Enforce interfaces and encapsulation for testable modules across teams.
Beginner
This week: one class with two private properties and one validating setter.
✓ Best practices
- Private properties by default, access via validating methods.
- Type properties and signatures (robustness + readability).
- Program to a contract (interfaces) to decouple and test.
✗ Common pitfalls
- Putting everything public (state corruptible from everywhere).
- Inheriting to copy code instead of specializing an “is a”.
- Confusing interface (contract) with inheritance (reuse).
Key takeaways
- OOP organises code into OBJECTS (data + behaviours). CLASS = blueprint; OBJECT = instance (new). $this = current; __construct = initialization.
- ENCAPSULATION: VISIBILITY (public/private/protected); private + validating getters/setters to protect state. INHERITANCE (extends): reuse and specialize.
- POLYMORPHISM (same method, different implementations) and ABSTRACTION. INTERFACES = contracts (decouple, test); TRAITS = sharing without inheritance.
- OOP is the CAPE of modern PHP and FRAMEWORKS: organise, reuse, maintain — a change of thinking that takes practice.
48h challenge — apply tomorrow
Write 1 encapsulated class (private + validating setter) and 1 child class overriding 1 method.
- I tell class (blueprint) apart from object (instance).
- My properties are private with validation.
- I inherit to specialize and contract via interface.
Frequently asked questions
Why switch to OOP when procedural works?
Procedural scatters data and functions with no structure: on a growing app, you no longer know which functions go with which data. OOP groups (object = data + behaviours), models the business (User, Order), protects state (encapsulation) and reuses (inheritance, traits) while decoupling (interfaces). It is the paradigm of level-4 frameworks — the cape to earn.
Encapsulation, inheritance, interfaces: how to grasp them concretely?
Encapsulation = protect and group: an account balance only changes via deposit/withdraw that check (never direct assignment). Inheritance = “is a kind of”: Dog extends Animal reuses and specializes (bark). Interface = contract: the class commits to providing methods, the rest of the code depends on the contract (testable). Trait = horizontal sharing when a single extends is not enough.
Why private properties + getters/setters?