De la procédurale à l'objet
Formation DWWM - 2025-2026
Comprendre le paradigme objet
Analogie : Une voiture 🚗
Avec des cookies 🍪 :
Problème : Code désorganisé, données séparées des fonctions
<?php
// Code procédural : données séparées
$voiture1_marque = "Peugeot";
$voiture1_vitesse = 0;
$voiture2_marque = "Renault";
$voiture2_vitesse = 0;
// Fonctions séparées
function demarrer(&$vitesse) {
$vitesse = 50;
}
demarrer($voiture1_vitesse);
// Quelle voiture ? Pas clair !
?>
Imaginez avec 100 voitures ! Il faudrait 200 variables (marque + vitesse pour chacune). C'est ingérable ! 😵
<?php
// Code orienté objet
class Voiture {
// Propriétés (données)
public $marque;
public $vitesse = 0;
// Méthodes (comportements)
public function demarrer() {
$this->vitesse = 50;
}
}
// Créer des objets
$voiture1 = new Voiture();
$voiture1->marque = "Peugeot";
$voiture1->demarrer(); // Clair !
$voiture2 = new Voiture();
$voiture2->marque = "Renault";
$voiture2->demarrer();
?>
new Voiture()En POO : Chaque objet "se gère lui-même". La voiture sait comment démarrer, vous lui demandez juste de le faire !
Classes, propriétés, méthodes
<?php
// Syntaxe de base
class NomDeLaClasse {
// Propriétés
// Méthodes
}
// Exemple
class Utilisateur {
// On va remplir ici
}
?>
<?php
class Utilisateur {
// Propriétés (caractéristiques d'un utilisateur)
public $nom;
public $prenom;
public $email;
public $age;
// Propriété avec valeur par défaut
public $actif = true;
}
?>
Analogie : Une fiche d'identité 🪪
$nom = "Dupont"$prenom = "Marie"$age = 25<?php
$user1 = new Utilisateur();
$user1->nom = "Dupont"; // Seulement pour user1
$user2 = new Utilisateur();
$user2->nom = "Martin"; // Seulement pour user2
echo $user1->nom; // "Dupont"
echo $user2->nom; // "Martin"
// Chacun a son propre nom !
?>
Pensez à des jumeaux : Même structure (2 bras, 2 jambes), mais noms et âges différents !
<?php
class Utilisateur {
public $nom;
public $age;
// Méthode : afficher les infos
public function afficher() {
echo "Nom : " . $this->nom . "\n";
echo "Âge : " . $this->age . " ans\n";
}
// Méthode : modifier l'âge
public function vieillir() {
$this->age++;
}
}
?>
$this->nom signifie "MON nom" (le nom de cet utilisateur)
<?php
class Utilisateur {
public $nom;
public function sePresenter() {
// $this->nom = MON nom (celui de cet objet)
echo "Bonjour, je suis " . $this->nom;
}
}
$user1 = new Utilisateur();
$user1->nom = "Marie";
$user1->sePresenter(); // "Bonjour, je suis Marie"
$user2 = new Utilisateur();
$user2->nom = "Jean";
$user2->sePresenter(); // "Bonjour, je suis Jean"
// Même méthode, résultats différents !
?>
<?php
// 1. Créer l'objet avec new
$user = new Utilisateur();
// 2. Définir les propriétés
$user->nom = "Dupont";
$user->age = 25;
// 3. Appeler les méthodes
$user->afficher();
// Affiche :
// Nom : Dupont
// Âge : 25 ans
$user->vieillir();
echo $user->age; // 26
?>
<?php
class Produit {
public $nom;
public $prix;
public $stock;
public function afficher() {
echo "Produit : " . $this->nom . "\n";
echo "Prix : " . $this->prix . " €\n";
}
public function prixTTC($tva = 20) {
return $this->prix * (1 + $tva / 100);
}
public function estDisponible() {
return $this->stock > 0;
}
}
$produit = new Produit();
$produit->nom = "Clavier";
$produit->prix = 89.99;
$produit->stock = 15;
echo $produit->prixTTC(); // 107.988
?>
public, private, protected
| Niveau | Symbole | Accessible depuis |
|---|---|---|
public |
🟢 | Partout |
private |
🔴 | Seulement dans la classe |
protected |
🟡 | Classe + enfants |
Analogie : Une maison 🏠
<?php
class Voiture {
public $marque;
public $couleur;
public function demarrer() {
echo "Vroum !";
}
}
$voiture = new Voiture();
$voiture->marque = "Peugeot"; // ✅ OK
$voiture->demarrer(); // ✅ OK
?>
<?php
class CompteBancaire {
private $solde = 0;
public function deposer($montant) {
$this->solde += $montant; // ✅ OK dans la classe
}
public function getSolde() {
return $this->solde; // ✅ OK dans la classe
}
}
$compte = new CompteBancaire();
$compte->deposer(100);
echo $compte->getSolde(); // 100 ✅
// echo $compte->solde; // ❌ ERREUR ! Private
?>
Scénario : Un compte bancaire
<?php
// ❌ AVEC public : DANGEREUX !
class CompteBancaire {
public $solde = 0;
}
$compte = new CompteBancaire();
$compte->solde = 1000000; // 😈 Je me donne 1 million !
// Pas de contrôle → Problème !
?>
<?php
// ✅ AVEC private : SÉCURISÉ !
class CompteBancaire {
private $solde = 0;
public function deposer($montant) {
// Vérifications avant modification
if ($montant > 0) {
$this->solde += $montant;
}
}
}
$compte = new CompteBancaire();
// $compte->solde = 1000000; // ❌ IMPOSSIBLE !
$compte->deposer(100); // ✅ Seule façon autorisée
?>
Dans la vraie vie :
private<?php
class Utilisateur {
// ❌ À ÉVITER
public $motDePasse;
// ✅ MIEUX
private $motDePasse;
public function setMotDePasse($mdp) {
// Validation avant modification
if (strlen($mdp) >= 8) {
$this->motDePasse = $mdp;
}
}
}
?>
L'encapsulation en action
Analogie : Un coffre-fort 🔐
<?php
// ❌ SANS getters/setters : DANGEREUX
class Utilisateur {
public $age; // N'importe qui peut modifier !
}
$user = new Utilisateur();
$user->age = 25; // OK
$user->age = -50; // 😱 Âge négatif accepté !
$user->age = 500; // 😱 Âge impossible accepté !
$user->age = "abc"; // 😱 Texte au lieu de nombre !
// Aucun contrôle → Données invalides
?>
<?php
// ✅ AVEC getters/setters : SÉCURISÉ
class Utilisateur {
private $age; // Protégé
public function setAge($age) {
// VALIDATION avant modification
if ($age >= 0 && $age <= 150) {
$this->age = $age;
} else {
throw new Exception("Âge invalide !");
}
}
public function getAge() {
return $this->age;
}
}
$user = new Utilisateur();
$user->setAge(25); // ✅ OK
$user->setAge(-50); // ❌ Exception !
$user->setAge(500); // ❌ Exception !
// Contrôle total → Données valides
?>
<?php
class Utilisateur {
private $nom;
private $email;
// Getter
public function getNom() {
return $this->nom;
}
public function getEmail() {
return $this->email;
}
}
$user = new Utilisateur();
echo $user->getNom(); // ✅ OK
?>
<?php
class Utilisateur {
private $nom;
private $age;
// Setter
public function setNom($nom) {
$this->nom = $nom;
}
public function setAge($age) {
$this->age = $age;
}
}
$user = new Utilisateur();
$user->setNom("Dupont"); // ✅ OK
?>
<?php
class Utilisateur {
private $age;
// Setter AVEC VALIDATION
public function setAge($age) {
if ($age > 0 && $age < 150) {
$this->age = $age;
} else {
throw new Exception("Âge invalide !");
}
}
public function getAge() {
return $this->age;
}
}
$user = new Utilisateur();
$user->setAge(25); // ✅ OK
$user->setAge(-5); // ❌ Exception
$user->setAge(200); // ❌ Exception
?>
<?php
class Utilisateur {
private $email;
public function setEmail($email) {
// Validation du format
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->email = $email;
} else {
throw new Exception("Email invalide !");
}
}
public function getEmail() {
return $this->email;
}
}
$user = new Utilisateur();
$user->setEmail("marie@example.com"); // ✅ OK
$user->setEmail("pas-un-email"); // ❌ Exception
?>
<?php
class Utilisateur {
private $id;
// Getter UNIQUEMENT
public function getId() {
return $this->id;
}
// PAS de setter !
// L'ID ne peut pas être modifié
}
$user = new Utilisateur();
echo $user->getId(); // ✅ OK
// $user->setId(42); // ❌ N'existe pas
?>
Initialisation automatique
new
<?php
class Utilisateur {
private $nom;
private $email;
// Constructeur : s'exécute automatiquement
public function __construct($nom, $email) {
$this->nom = $nom;
$this->email = $email;
echo "Nouvel utilisateur créé !\n";
}
}
// Dès qu'on fait "new", le constructeur s'exécute !
$user = new Utilisateur("Dupont", "dupont@example.com");
// Affiche automatiquement : "Nouvel utilisateur créé !"
?>
Analogie : Naissance d'un bébé 👶
<?php
class Utilisateur {
private $nom;
private $email;
public function __construct($nom, $email) {
echo "1. Constructeur appelé !\n";
$this->nom = $nom;
$this->email = $email;
echo "2. Propriétés définies !\n";
}
}
echo "Avant new\n";
$user = new Utilisateur("Dupont", "dupont@example.com");
echo "Après new\n";
// Affichage :
// Avant new
// 1. Constructeur appelé !
// 2. Propriétés définies !
// Après new
?>
Déroulement :
new Utilisateur(...)__construct()$user<?php
class Utilisateur {
private $nom;
private $email;
private $age;
public function __construct($nom, $email, $age) {
$this->nom = $nom;
$this->email = $email;
$this->age = $age;
}
}
?>
<?php
class Utilisateur {
private $nom;
private $email;
public function __construct($nom, $email) {
if (empty($nom)) {
throw new Exception("Nom vide");
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new Exception("Email invalide");
}
$this->nom = $nom;
$this->email = $email;
}
}
$user = new Utilisateur("Dupont", "dupont@example.com"); // ✅
$user = new Utilisateur("", "invalide"); // ❌ Exception
?>
<?php
class Utilisateur {
private $nom;
private $actif;
private $role;
public function __construct(
$nom,
$actif = true, // Défaut
$role = "utilisateur" // Défaut
) {
$this->nom = $nom;
$this->actif = $actif;
$this->role = $role;
}
}
$user1 = new Utilisateur("Dupont");
// actif = true, role = "utilisateur"
$user2 = new Utilisateur("Martin", false, "admin");
?>
Propriétés et méthodes de classe
Analogie : Compteur de personnes dans un magasin 🔢
<?php
class Utilisateur {
private $nom;
// STATIC : partagé par TOUS les utilisateurs
private static $compteur = 0;
public function __construct($nom) {
$this->nom = $nom;
// Chaque nouvel utilisateur incrémente LE MÊME compteur
self::$compteur++;
echo "Utilisateur #{self::$compteur} créé : {$nom}\n";
}
public static function getCompteur() {
return self::$compteur;
}
}
$user1 = new Utilisateur("Marie");
// Affiche : Utilisateur #1 créé : Marie
$user2 = new Utilisateur("Jean");
// Affiche : Utilisateur #2 créé : Jean
$user3 = new Utilisateur("Paul");
// Affiche : Utilisateur #3 créé : Paul
echo Utilisateur::getCompteur(); // 3
// Pas besoin d'objet pour lire le compteur !
?>
Règle simple :
<?php
class MathUtils {
// Méthodes static = fonctions utilitaires
public static function carre($n) {
return $n * $n;
}
public static function cube($n) {
return $n * $n * $n;
}
}
// On utilise DIRECTEMENT sans créer d'objet
echo MathUtils::carre(5); // 25
echo MathUtils::cube(3); // 27
// Pas besoin de faire : $math = new MathUtils();
?>
Analogie : C'est comme une calculatrice. Pas besoin d'acheter une calculatrice personnelle pour faire 2+2. Vous utilisez juste la fonction de calcul !
<?php
class Utilisateur {
private $nom;
private static $compteur = 0;
public function __construct($nom) {
$this->nom = $nom;
self::$compteur++;
}
public static function getCompteur() {
return self::$compteur;
}
}
$user1 = new Utilisateur("Dupont");
echo Utilisateur::getCompteur(); // 1
$user2 = new Utilisateur("Martin");
echo Utilisateur::getCompteur(); // 2
// Pas besoin de créer un objet !
?>
<?php
class MathUtils {
public static function carre($nombre) {
return $nombre * $nombre;
}
public static function cube($nombre) {
return $nombre * $nombre * $nombre;
}
}
// Utilisation SANS créer d'objet
echo MathUtils::carre(5); // 25
echo MathUtils::cube(3); // 27
?>
<?php
class Utilisateur {
private $nom; // Instance
private static $compteur; // Static
public function getNom() {
return $this->nom; // $this
}
public static function getCompteur() {
return self::$compteur; // self
}
}
?>
Type hints
<?php
class Utilisateur {
private string $nom;
private int $age;
public function __construct(string $nom, int $age) {
$this->nom = $nom;
$this->age = $age;
}
public function getNom(): string {
return $this->nom;
}
public function getAge(): int {
return $this->age;
}
}
$user = new Utilisateur("Dupont", 25); // ✅
$user = new Utilisateur("Dupont", "25"); // ❌ Erreur
?>
| Type | Description | Exemple |
|---|---|---|
| string | Chaîne | "Dupont" |
| int | Entier | 25 |
| float | Décimal | 19.99 |
| bool | Booléen | true/false |
| array | Tableau | [1, 2, 3] |
<?php
class Utilisateur {
private string $nom;
private ?string $telephone; // Peut être null
public function __construct(
string $nom,
?string $telephone = null
) {
$this->nom = $nom;
$this->telephone = $telephone;
}
public function getTelephone(): ?string {
return $this->telephone;
}
}
$user1 = new Utilisateur("Dupont"); // tel = null ✅
$user2 = new Utilisateur("Martin", "0601020304"); // ✅
?>
SQL dans la POO
<?php
class Database {
private static ?PDO $pdo = null;
public static function getConnection(): PDO {
if (self::$pdo === null) {
self::$pdo = new PDO(
'mysql:host=localhost;dbname=ma_base',
'user',
'password'
);
self::$pdo->setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
}
return self::$pdo;
}
}
?>
<?php
class Article {
private ?int $id = null;
private string $titre;
private string $contenu;
public function __construct(string $titre, string $contenu) {
$this->titre = $titre;
$this->contenu = $contenu;
}
public function getId(): ?int {
return $this->id;
}
public function getTitre(): string {
return $this->titre;
}
public function getContenu(): string {
return $this->contenu;
}
}
?>
<?php
class Article {
// ... propriétés ...
public function save(): bool {
$pdo = Database::getConnection();
if ($this->id === null) {
// INSERT
$sql = "INSERT INTO articles (titre, contenu)
VALUES (:titre, :contenu)";
$stmt = $pdo->prepare($sql);
$result = $stmt->execute([
':titre' => $this->titre,
':contenu' => $this->contenu
]);
if ($result) {
$this->id = (int) $pdo->lastInsertId();
}
return $result;
} else {
// UPDATE
$sql = "UPDATE articles
SET titre = :titre, contenu = :contenu
WHERE id = :id";
$stmt = $pdo->prepare($sql);
return $stmt->execute([
':titre' => $this->titre,
':contenu' => $this->contenu,
':id' => $this->id
]);
}
}
}
?>
<?php
class Article {
// ... autres méthodes ...
public static function findById(int $id): ?Article {
$pdo = Database::getConnection();
$sql = "SELECT * FROM articles WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([':id' => $id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$data) {
return null;
}
$article = new Article($data['titre'], $data['contenu']);
$article->id = (int) $data['id'];
return $article;
}
}
// Utilisation
$article = Article::findById(5);
if ($article) {
echo $article->getTitre();
}
?>
<?php
class Article {
public static function findAll(): array {
$pdo = Database::getConnection();
$sql = "SELECT * FROM articles ORDER BY id DESC";
$stmt = $pdo->query($sql);
$articles = [];
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
$article = new Article($data['titre'], $data['contenu']);
$article->id = (int) $data['id'];
$articles[] = $article;
}
return $articles;
}
}
// Utilisation
$articles = Article::findAll();
foreach ($articles as $article) {
echo $article->getTitre() . "\n";
}
?>
<?php
// CRÉER
$article = new Article("Mon titre", "Mon contenu");
$article->save(); // INSERT
// MODIFIER
$article->setTitre("Nouveau titre");
$article->save(); // UPDATE
// RÉCUPÉRER
$article = Article::findById(5);
echo $article->getTitre();
// LISTE
$articles = Article::findAll();
// SUPPRIMER
$article->delete();
?>
Sécurité et validation
<?php
class Utilisateur {
private string $nom;
public function setNom(string $nom): void {
// Nettoyer
$nom = trim($nom);
// Vérifier non vide
if (empty($nom)) {
throw new Exception("Nom vide");
}
// Vérifier longueur
if (strlen($nom) < 2 || strlen($nom) > 50) {
throw new Exception("Nom : 2-50 caractères");
}
$this->nom = $nom;
}
}
?>
<?php
class Utilisateur {
private string $email;
public function setEmail(string $email): void {
$email = trim(strtolower($email));
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new Exception("Email invalide");
}
$this->email = $email;
}
}
$user = new Utilisateur();
$user->setEmail("marie@example.com"); // ✅
$user->setEmail("pas-email"); // ❌
?>
<?php
class Utilisateur {
private string $motDePasse;
public function setMotDePasse(string $mdp): void {
if (strlen($mdp) < 8) {
throw new Exception("Min 8 caractères");
}
if (!preg_match('/[A-Z]/', $mdp)) {
throw new Exception("Une majuscule requise");
}
if (!preg_match('/[0-9]/', $mdp)) {
throw new Exception("Un chiffre requis");
}
// Hasher
$this->motDePasse = password_hash($mdp, PASSWORD_DEFAULT);
}
}
?>
<?php
class Validator {
public static function email(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
public static function range($value, $min, $max): bool {
return $value >= $min && $value <= $max;
}
public static function length(string $str, int $min, int $max): bool {
$len = strlen($str);
return $len >= $min && $len <= $max;
}
}
if (!Validator::email($email)) {
throw new Exception("Email invalide");
}
?>
<?php
class Article {
// ❌ DANGEREUX
public static function findDangereux($titre) {
$sql = "SELECT * FROM articles WHERE titre = '$titre'";
// Injection possible !
}
// ✅ SÛR : requête préparée
public static function findByTitre(string $titre): array {
$pdo = Database::getConnection();
$sql = "SELECT * FROM articles WHERE titre = :titre";
$stmt = $pdo->prepare($sql);
$stmt->execute([':titre' => $titre]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
?>
<?php
class Article {
private string $titre;
public function setTitre(string $titre): void {
// Échapper les balises HTML
$this->titre = htmlspecialchars($titre, ENT_QUOTES, 'UTF-8');
}
}
$article = new Article();
$article->setTitre("Titre avec balise script");
// Les balises sont échappées, pas exécutées
?>
| Contexte | Solution |
|---|---|
| filter_var FILTER_VALIDATE_EMAIL | |
| SQL | Requêtes préparées PDO |
| HTML | htmlspecialchars |
| Mot de passe | password_hash |
| Concept | Description |
|---|---|
| Classe | Modèle pour créer des objets |
| Objet | Instance d'une classe |
| Propriété | Variable de classe |
| Méthode | Fonction de classe |
| Visibilité | public/private/protected |
| Getter/Setter | Accès contrôlé aux propriétés |
| Constructeur | Initialisation automatique |
| Static | Appartient à la classe |
Questions ?