đ Cours Complet : Programmation OrientĂ©e Objet
2 crédits (30 heures) - CM, TD, TP, TPE
đ Chapitre 1 : Introduction aux concepts orientĂ©s objets
1.1 Définition et Philosophie
đŻ DĂ©finition : La Programmation OrientĂ©e Objet (POO) est un paradigme de programmation qui organise le code autour dâobjets plutĂŽt que de fonctions et de logique procĂ©durale.
đĄ Analogie de la vie rĂ©elle : Imaginez une voiture :
- Elle a des caractéristiques : couleur, marque, vitesse
- Elle a des comportements : démarrer, accélérer, freiner
- Elle cache sa complexitĂ© : vous nâavez pas besoin de savoir comment fonctionne le moteur pour conduire
1.2 Les 4 piliers de la POO
| Pilier | Description | Exemple Réel |
|---|---|---|
| Encapsulation | Regrouper données et méthodes | Un téléphone cache ses circuits internes |
| HĂ©ritage | CrĂ©er Ă partir de lâexistant | Une voiture Ă©lectrique hĂ©rite des propriĂ©tĂ©s dâune voiture |
| Polymorphisme | Plusieurs formes | Un bouton âplayâ fonctionne pour musique, vidĂ©o, etc. |
| Abstraction | Simplifier la complexité | Un volant = interface simple pour systÚme complexe |
1.3 Avantages de la POO
<?php
declare(strict_types=1);
// â SANS POO - Code procĂ©dural dĂ©sorganisĂ©
$voiture1_marque = "Toyota";
$voiture1_vitesse = 0;
$voiture2_marque = "Peugeot";
$voiture2_vitesse = 0;
function accelerer_voiture(&$vitesse, $augmentation) {
$vitesse += $augmentation;
}
// â
AVEC POO - Code organisé et réutilisable
class Voiture {
private string $marque;
private int $vitesse = 0;
public function __construct(string $marque) {
$this->marque = $marque;
}
public function accelerer(int $augmentation): void {
$this->vitesse += $augmentation;
}
}
$voiture1 = new Voiture("Toyota");
$voiture2 = new Voiture("Peugeot");
?>
đ Chapitre 2 : Objets et Classes
2.1 Définitions Fondamentales
đïž Classe : Un plan, un modĂšle, un moule pour crĂ©er des objets đŠ Objet : Une instance concrĂšte créée Ă partir dâune classe đ§ Attribut/PropriĂ©tĂ© : Une caractĂ©ristique de lâobjet ⥠MĂ©thode : Une action que lâobjet peut effectuer
đĄ Analogie :
- Classe = Plan dâarchitecte dâune maison
- Objet = Maison construite selon ce plan
- Attributs = Nombre de chambres, couleur, surface
- Méthodes = Ouvrir la porte, allumer les lumiÚres
2.2 Syntaxe de base en PHP 8.4
<?php
declare(strict_types=1);
// DĂCLARATION D'UNE CLASSE
class Personne {
// ATTRIBUTS (Propriétés)
public string $nom; // Public : accessible partout
private int $age; // Private : accessible uniquement dans la classe
protected string $adresse; // Protected : accessible dans la classe et ses enfants
// CONSTRUCTEUR - Méthode spéciale appelée à la création
public function __construct(string $nom, int $age, string $adresse) {
$this->nom = $nom; // $this représente l'objet actuel
$this->age = $age;
$this->adresse = $adresse;
}
// MĂTHODES - Actions de l'objet
public function sePresenter(): string {
return "Je m'appelle {$this->nom} et j'ai {$this->age} ans.";
}
public function vieillir(): void {
$this->age++;
}
// GETTER - Obtenir une valeur privée
public function getAge(): int {
return $this->age;
}
// SETTER - Modifier une valeur privée avec validation
public function setAge(int $nouvelAge): void {
if ($nouvelAge < 0 || $nouvelAge > 150) {
throw new InvalidArgumentException("Ăge invalide");
}
$this->age = $nouvelAge;
}
}
// CRĂATION D'OBJETS (Instanciation)
$personne1 = new Personne("Alice", 25, "Paris");
$personne2 = new Personne("Bob", 30, "Lyon");
// UTILISATION DES OBJETS
echo $personne1->sePresenter() . PHP_EOL; // Appel de méthode
echo "Nom : " . $personne1->nom . PHP_EOL; // AccÚs à propriété publique
// echo $personne1->age; // ERREUR ! age est privé
$personne1->vieillir();
echo "Nouvel Ăąge : " . $personne1->getAge() . PHP_EOL;
?>
2.3 Exemple concret : SystĂšme Bancaire
<?php
declare(strict_types=1);
class CompteBancaire {
// Propriétés
private string $numero;
private string $titulaire;
private float $solde;
private array $historique = [];
// PHP 8.1+ : propriĂ©tĂ© readonly (ne peut ĂȘtre modifiĂ©e aprĂšs initialisation)
public readonly DateTime $dateOuverture;
// Constructeur
public function __construct(string $titulaire, float $depotInitial = 0) {
$this->numero = $this->genererNumero();
$this->titulaire = $titulaire;
$this->solde = $depotInitial;
$this->dateOuverture = new DateTime();
if ($depotInitial > 0) {
$this->ajouterHistorique("Ouverture avec dépÎt", $depotInitial);
}
}
// Méthode privée (utilisée uniquement en interne)
private function genererNumero(): string {
return 'CB' . date('Y') . rand(10000, 99999);
}
private function ajouterHistorique(string $operation, float $montant): void {
$this->historique[] = [
'date' => new DateTime(),
'operation' => $operation,
'montant' => $montant,
'solde' => $this->solde
];
}
// Méthodes publiques (interface de la classe)
public function deposer(float $montant): void {
if ($montant <= 0) {
throw new InvalidArgumentException("Le montant doit ĂȘtre positif");
}
$this->solde += $montant;
$this->ajouterHistorique("DépÎt", $montant);
echo "â
DépÎt de {$montant}⏠effectué\n";
}
public function retirer(float $montant): bool {
if ($montant <= 0) {
throw new InvalidArgumentException("Le montant doit ĂȘtre positif");
}
if ($montant > $this->solde) {
echo "â Solde insuffisant\n";
return false;
}
$this->solde -= $montant;
$this->ajouterHistorique("Retrait", -$montant);
echo "â
Retrait de {$montant}⏠effectué\n";
return true;
}
public function consulterSolde(): float {
return $this->solde;
}
public function afficherReleve(): void {
echo "\n=== RELEVĂ DE COMPTE ===\n";
echo "Compte N° : {$this->numero}\n";
echo "Titulaire : {$this->titulaire}\n";
echo "Solde actuel : {$this->solde}âŹ\n";
echo "\nDerniÚres opérations :\n";
foreach (array_slice($this->historique, -5) as $op) {
printf(" %s - %s : %+.2f⏠(Solde: %.2fâŹ)\n",
$op['date']->format('d/m/Y H:i'),
$op['operation'],
$op['montant'],
$op['solde']
);
}
}
}
// Utilisation
$compte = new CompteBancaire("Jean Dupont", 1000);
$compte->deposer(500);
$compte->retirer(200);
$compte->retirer(2000); // Ăchec
$compte->afficherReleve();
?>
đ Chapitre 3 : Encapsulation et masquage dâinformation
3.1 Définition et Principes
đ Encapsulation : MĂ©canisme qui consiste Ă :
- Regrouper les données et les méthodes dans une classe
- Cacher les dĂ©tails dâimplĂ©mentation
- ContrĂŽler lâaccĂšs aux donnĂ©es
đĄ Analogie : Un distributeur automatique
- Vous voyez les boutons (interface publique)
- Vous ne voyez pas les mécanismes internes (implémentation privée)
- Vous interagissez uniquement via les boutons
3.2 Niveaux de visibilité
<?php
declare(strict_types=1);
class Voiture {
// PUBLIC : Accessible de partout
public string $couleur = "rouge";
// PRIVATE : Accessible uniquement dans cette classe
private float $niveauEssence = 50.0;
// PROTECTED : Accessible dans cette classe et ses enfants
protected int $kilometrage = 0;
// Méthodes publiques pour interagir avec les données privées
public function fairePlein(): void {
$this->niveauEssence = 100.0; // OK : accĂšs interne
}
public function getNiveauEssence(): float {
return $this->niveauEssence;
}
public function rouler(int $km): void {
if ($this->niveauEssence <= 0) {
echo "✠RĂ©servoir vide !\n";
return;
}
$this->kilometrage += $km;
$this->niveauEssence -= $km * 0.08; // Consommation
if ($this->niveauEssence < 0) {
$this->niveauEssence = 0;
}
}
}
// Utilisation
$maVoiture = new Voiture();
// â
OK : propriété publique
$maVoiture->couleur = "bleu";
echo "Couleur : " . $maVoiture->couleur . PHP_EOL;
// â ERREUR : propriĂ©tĂ© privĂ©e
// $maVoiture->niveauEssence = 100; // Fatal Error
// â
OK : utilisation de l'interface publique
$maVoiture->fairePlein();
echo "Essence : " . $maVoiture->getNiveauEssence() . "%\n";
$maVoiture->rouler(200);
echo "Essence aprĂšs trajet : " . $maVoiture->getNiveauEssence() . "%\n";
?>
3.3 Exemple pratique : Mot de passe sécurisé
<?php
declare(strict_types=1);
class Utilisateur {
private string $nom;
private string $email;
private string $motDePasseHash; // Jamais stocké en clair !
public function __construct(string $nom, string $email, string $motDePasse) {
$this->nom = $nom;
$this->setEmail($email);
$this->setMotDePasse($motDePasse);
}
// Validation et encapsulation pour l'email
private function setEmail(string $email): void {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Email invalide");
}
$this->email = $email;
}
// Le mot de passe n'est jamais accessible directement
private function setMotDePasse(string $motDePasse): void {
if (strlen($motDePasse) < 8) {
throw new InvalidArgumentException("Le mot de passe doit faire au moins 8 caractĂšres");
}
// Hashage sécurisé (jamais en clair !)
$this->motDePasseHash = password_hash($motDePasse, PASSWORD_DEFAULT);
}
// Vérification sans exposer le hash
public function verifierMotDePasse(string $motDePasse): bool {
return password_verify($motDePasse, $this->motDePasseHash);
}
public function changerMotDePasse(string $ancienMdp, string $nouveauMdp): bool {
if (!$this->verifierMotDePasse($ancienMdp)) {
echo "â Ancien mot de passe incorrect\n";
return false;
}
$this->setMotDePasse($nouveauMdp);
echo "â
Mot de passe changé avec succÚs\n";
return true;
}
// Getters pour les données non sensibles
public function getNom(): string {
return $this->nom;
}
public function getEmail(): string {
return $this->email;
}
// PAS de getter pour le mot de passe !
}
// Utilisation
$user = new Utilisateur("Alice", "alice@example.com", "MonSuperMotDePasse123");
echo "Utilisateur : " . $user->getNom() . PHP_EOL;
echo "Email : " . $user->getEmail() . PHP_EOL;
// Impossible d'accéder au mot de passe
// echo $user->motDePasseHash; // ERREUR
// Vérification sécurisée
if ($user->verifierMotDePasse("MonSuperMotDePasse123")) {
echo "â
Connexion réussie\n";
}
$user->changerMotDePasse("MauvaisMdp", "NouveauMdp456"); // Ăchec
$user->changerMotDePasse("MonSuperMotDePasse123", "NouveauMdp456"); // SuccĂšs
?>
đ Chapitre 4 : AgrĂ©gation et DĂ©composition
4.1 Définitions et Différences
đ Association : Relation entre classes đ AgrĂ©gation : Relation âutiliseâ ou âa unâ (faible) đ§ Composition : Relation âfait partie deâ (forte)
| Aspect | Agrégation | Composition |
|---|---|---|
| Dépendance | Faible | Forte |
| Cycle de vie | Indépendant | Dépendant |
| Exemple | Ăcole â â Professeur | Voiture â â Moteur |
| Symbole UML | Losange vide â | Losange plein â |
4.2 Agrégation : Relation faible
<?php
declare(strict_types=1);
// Les livres peuvent exister sans bibliothĂšque
class Livre {
private string $titre;
private string $auteur;
private string $isbn;
public function __construct(string $titre, string $auteur, string $isbn) {
$this->titre = $titre;
$this->auteur = $auteur;
$this->isbn = $isbn;
}
public function getTitre(): string {
return $this->titre;
}
public function getInfo(): string {
return "{$this->titre} par {$this->auteur} (ISBN: {$this->isbn})";
}
}
// La bibliothĂšque agrĂšge des livres existants
class Bibliotheque {
private string $nom;
/** @var Livre[] */
private array $livres = [];
public function __construct(string $nom) {
$this->nom = $nom;
}
// Agrégation : on ajoute un livre existant
public function ajouterLivre(Livre $livre): void {
$this->livres[] = $livre;
echo "đ '{$livre->getTitre()}' ajoutĂ© Ă {$this->nom}\n";
}
public function retirerLivre(Livre $livre): void {
$index = array_search($livre, $this->livres);
if ($index !== false) {
unset($this->livres[$index]);
$this->livres = array_values($this->livres);
echo "đ€ '{$livre->getTitre()}' retirĂ© de {$this->nom}\n";
}
}
public function listerLivres(): void {
echo "\nđ Livres dans {$this->nom}:\n";
foreach ($this->livres as $livre) {
echo " - " . $livre->getInfo() . "\n";
}
}
public function __destruct() {
echo "đïž Fermeture de {$this->nom}\n";
// Les livres continuent d'exister !
}
}
// Exemple d'utilisation
$livre1 = new Livre("1984", "George Orwell", "978-0452284234");
$livre2 = new Livre("Le Petit Prince", "Antoine de Saint-Exupéry", "978-0156012195");
$livre3 = new Livre("Harry Potter", "J.K. Rowling", "978-0439708180");
$biblio1 = new Bibliotheque("BibliothĂšque Centrale");
$biblio2 = new Bibliotheque("BibliothĂšque de Quartier");
// Un livre peut ĂȘtre dans plusieurs bibliothĂšques (prĂȘt inter-bibliothĂšques)
$biblio1->ajouterLivre($livre1);
$biblio1->ajouterLivre($livre2);
$biblio2->ajouterLivre($livre2); // Le mĂȘme livre dans une autre bibliothĂšque
$biblio2->ajouterLivre($livre3);
$biblio1->listerLivres();
$biblio2->listerLivres();
// Les livres existent indépendamment des bibliothÚques
unset($biblio1);
echo "\nđ Le livre '{$livre1->getTitre()}' existe toujours aprĂšs fermeture de la bibliothĂšque\n";
?>
4.3 Composition : Relation forte
<?php
declare(strict_types=1);
// Le processeur n'existe pas sans l'ordinateur
class Processeur {
private string $modele;
private float $frequence;
private int $coeurs;
public function __construct(string $modele, float $frequence, int $coeurs) {
$this->modele = $modele;
$this->frequence = $frequence;
$this->coeurs = $coeurs;
echo "đ§ Processeur {$modele} installĂ©\n";
}
public function calculer(): void {
echo "⥠Processeur {$this->modele} calcule à {$this->frequence}GHz\n";
}
public function __destruct() {
echo "đïž Processeur {$this->modele} dĂ©truit\n";
}
}
// La RAM n'existe pas sans l'ordinateur
class Memoire {
private int $capacite;
private string $type;
public function __construct(int $capacite, string $type = "DDR4") {
$this->capacite = $capacite;
$this->type = $type;
echo "đ§ MĂ©moire {$capacite}GB {$type} installĂ©e\n";
}
public function stocker(): void {
echo "đŸ Stockage en mĂ©moire {$this->type} ({$this->capacite}GB)\n";
}
public function __destruct() {
echo "đïž MĂ©moire dĂ©truite\n";
}
}
// L'ordinateur crée et possÚde ses composants
class Ordinateur {
private string $marque;
private Processeur $processeur; // Composition
private Memoire $memoire; // Composition
public function __construct(string $marque, string $cpu, float $freq, int $ram) {
$this->marque = $marque;
echo "đ„ïž Construction de l'ordinateur {$marque}\n";
// L'ordinateur CRĂE ses composants (composition)
$this->processeur = new Processeur($cpu, $freq, 8);
$this->memoire = new Memoire($ram);
echo "â
Ordinateur {$marque} assemblé\n\n";
}
public function demarrer(): void {
echo "đ DĂ©marrage de {$this->marque}\n";
$this->processeur->calculer();
$this->memoire->stocker();
}
public function __destruct() {
echo "\nâ Destruction de l'ordinateur {$this->marque}\n";
// Les composants sont automatiquement détruits
}
}
// Utilisation
echo "=== CRĂATION ===\n";
$monPC = new Ordinateur("Dell", "Intel i7", 3.8, 16);
echo "=== UTILISATION ===\n";
$monPC->demarrer();
echo "\n=== DESTRUCTION ===\n";
unset($monPC); // L'ordinateur ET ses composants sont détruits
// On ne peut pas créer un processeur seul (il fait partie de l'ordinateur)
// $cpu = new Processeur("AMD", 3.5, 6); // N'a pas de sens sans ordinateur
?>
đ Chapitre 5 : GĂ©nĂ©ralisation et SpĂ©cialisation
5.1 Concepts
âŹïž GĂ©nĂ©ralisation : Extraire les caractĂ©ristiques communes âŹïž SpĂ©cialisation : CrĂ©er des versions plus spĂ©cifiques
đĄ Analogie :
Animal (général)
â
ââââââââŒâââââââ
â â â
MammifĂšre Oiseau Poisson
â
âââââŒââââ
â â â
Chat Chien Cheval (spécifique)
5.2 Implémentation de la hiérarchie
<?php
declare(strict_types=1);
// NIVEAU 1 : Classe la plus générale
abstract class Vehicule {
protected string $marque;
protected string $modele;
protected int $annee;
protected float $prix;
public function __construct(string $marque, string $modele, int $annee, float $prix) {
$this->marque = $marque;
$this->modele = $modele;
$this->annee = $annee;
$this->prix = $prix;
}
// Méthode commune à tous les véhicules
public function afficherInfo(): void {
echo "đ {$this->marque} {$this->modele} ({$this->annee}) - {$this->prix}âŹ\n";
}
// Méthodes abstraites à implémenter
abstract public function demarrer(): void;
abstract public function arreter(): void;
abstract public function calculerTaxe(): float;
}
// NIVEAU 2 : Spécialisation par type de terrain
abstract class VehiculeTerrestre extends Vehicule {
protected int $nombreRoues;
public function __construct(string $marque, string $modele, int $annee, float $prix, int $roues) {
parent::__construct($marque, $modele, $annee, $prix);
$this->nombreRoues = $roues;
}
public function rouler(): void {
echo "đ Roule sur {$this->nombreRoues} roues\n";
}
}
abstract class VehiculeAerien extends Vehicule {
protected float $altitudeMax;
public function __construct(string $marque, string $modele, int $annee, float $prix, float $altitude) {
parent::__construct($marque, $modele, $annee, $prix);
$this->altitudeMax = $altitude;
}
public function voler(): void {
echo "âïž Vole jusqu'Ă {$this->altitudeMax}m d'altitude\n";
}
}
// NIVEAU 3 : Classes concrÚtes spécialisées
class Voiture extends VehiculeTerrestre {
private int $nombrePortes;
private string $typeCarburant;
public function __construct(
string $marque,
string $modele,
int $annee,
float $prix,
int $portes,
string $carburant
) {
parent::__construct($marque, $modele, $annee, $prix, 4); // 4 roues
$this->nombrePortes = $portes;
$this->typeCarburant = $carburant;
}
public function demarrer(): void {
echo "đ La voiture dĂ©marre (moteur {$this->typeCarburant})\n";
}
public function arreter(): void {
echo "đ La voiture s'arrĂȘte\n";
}
public function calculerTaxe(): float {
$taxeBase = 200;
if ($this->typeCarburant === "electrique") {
return 0; // Pas de taxe pour électrique
}
return $taxeBase + ($this->annee < 2015 ? 100 : 0);
}
}
class Moto extends VehiculeTerrestre {
private int $cylindree;
public function __construct(
string $marque,
string $modele,
int $annee,
float $prix,
int $cylindree
) {
parent::__construct($marque, $modele, $annee, $prix, 2); // 2 roues
$this->cylindree = $cylindree;
}
public function demarrer(): void {
echo "đïž La moto dĂ©marre (cylindrĂ©e {$this->cylindree}cc)\n";
}
public function arreter(): void {
echo "đïž La moto s'arrĂȘte\n";
}
public function calculerTaxe(): float {
return $this->cylindree > 125 ? 150 : 50;
}
public function faireLaRoue(): void {
echo "đïž La moto fait une roue arriĂšre !\n";
}
}
class Avion extends VehiculeAerien {
private int $nombrePassagers;
public function __construct(
string $marque,
string $modele,
int $annee,
float $prix,
int $passagers
) {
parent::__construct($marque, $modele, $annee, $prix, 10000);
$this->nombrePassagers = $passagers;
}
public function demarrer(): void {
echo "âïž L'avion dĂ©marre ses moteurs\n";
}
public function arreter(): void {
echo "âïž L'avion coupe ses moteurs\n";
}
public function calculerTaxe(): float {
return $this->nombrePassagers * 100;
}
public function decoller(): void {
echo "đ« L'avion dĂ©colle avec {$this->nombrePassagers} passagers\n";
}
}
// Utilisation de la hiérarchie
echo "=== PARC DE VĂHICULES ===\n\n";
$voiture = new Voiture("Tesla", "Model 3", 2023, 45000, 4, "electrique");
$moto = new Moto("Yamaha", "MT-07", 2022, 8000, 700);
$avion = new Avion("Boeing", "737", 2020, 50000000, 180);
// Méthodes communes (héritage)
$voiture->afficherInfo();
$voiture->demarrer();
$voiture->rouler();
echo "Taxe: {$voiture->calculerTaxe()}âŹ\n\n";
$moto->afficherInfo();
$moto->demarrer();
$moto->rouler();
$moto->faireLaRoue(); // Méthode spécifique
echo "Taxe: {$moto->calculerTaxe()}âŹ\n\n";
$avion->afficherInfo();
$avion->demarrer();
$avion->decoller(); // Méthode spécifique
$avion->voler();
echo "Taxe: {$avion->calculerTaxe()}âŹ\n";
?>
đ Chapitre 6 : HĂ©ritage
6.1 Définition et Types
đ§Ź HĂ©ritage : MĂ©canisme permettant Ă une classe (enfant) dâhĂ©riter des propriĂ©tĂ©s et mĂ©thodes dâune autre classe (parent).
Types dâhĂ©ritage :
- Simple : Une classe hĂ©rite dâune seule classe parent
- Multiple : Une classe hérite de plusieurs classes (non supporté en PHP)
- Multiniveau : A â B â C (chaĂźne dâhĂ©ritage)
- HiĂ©rarchique : Plusieurs classes hĂ©ritent dâune mĂȘme classe parent
6.2 Syntaxe et Mécanismes
<?php
declare(strict_types=1);
// CLASSE PARENT (Base)
class Animal {
protected string $nom; // protected = accessible aux enfants
protected int $age;
protected float $poids;
private string $id; // private = NON accessible aux enfants
public function __construct(string $nom, int $age, float $poids) {
$this->nom = $nom;
$this->age = $age;
$this->poids = $poids;
$this->id = uniqid('ANIMAL_');
}
public function manger(float $quantite): void {
$this->poids += $quantite * 0.1;
echo "{$this->nom} mange et prend du poids\n";
}
public function dormir(): void {
echo "{$this->nom} dort... đ€\n";
}
public function vieillir(): void {
$this->age++;
echo "{$this->nom} a maintenant {$this->age} ans\n";
}
public function getInfo(): string {
return "{$this->nom} - {$this->age} ans - {$this->poids}kg";
}
}
// CLASSE ENFANT 1 : Héritage simple
class Chien extends Animal { // extends = hérite de
private string $race;
private bool $dresse;
public function __construct(string $nom, int $age, float $poids, string $race) {
// parent:: appelle le constructeur du parent
parent::__construct($nom, $age, $poids);
$this->race = $race;
$this->dresse = false;
}
// NOUVELLE méthode spécifique aux chiens
public function aboyer(): void {
echo "{$this->nom} aboie: WOUAF WOUAF! đ\n";
}
// REDĂFINITION (Override) d'une mĂ©thode parent
public function manger(float $quantite): void {
// On peut appeler la méthode parent
parent::manger($quantite);
echo "Le chien {$this->nom} remue la queue\n";
}
// EXTENSION d'une méthode parent
public function getInfo(): string {
$infoBase = parent::getInfo();
return $infoBase . " - Race: {$this->race}" .
($this->dresse ? " (Dressé)" : " (Non dressé)");
}
public function dresser(): void {
$this->dresse = true;
echo "{$this->nom} est maintenant dressé\n";
}
}
// CLASSE ENFANT 2
class Chat extends Animal {
private int $vies = 9;
public function miauler(): void {
echo "{$this->nom} miaule: MIAOU! đ\n";
}
public function ronronner(): void {
echo "{$this->nom} ronronne de plaisir... đ\n";
}
// Redéfinition spécifique
public function dormir(): void {
echo "{$this->nom} fait une sieste au soleil âïž\n";
}
public function perdreUneVie(): void {
if ($this->vies > 0) {
$this->vies--;
echo "{$this->nom} perd une vie! Reste: {$this->vies}\n";
}
}
}
// CLASSE ENFANT 3 : Héritage multiniveau
class ChienPolicier extends Chien {
private string $matricule;
private array $competences = [];
public function __construct(string $nom, int $age, float $poids, string $race) {
parent::__construct($nom, $age, $poids, $race);
$this->matricule = 'K9_' . rand(1000, 9999);
$this->dresser(); // Automatiquement dressé
$this->competences = ['Recherche', 'Attaque', 'Détection'];
}
public function rechercher(): void {
echo "đ {$this->nom} (Matricule: {$this->matricule}) recherche...\n";
}
public function detecterDrogue(): bool {
$trouve = rand(0, 1) === 1;
echo $trouve ? "đš Drogue dĂ©tectĂ©e!\n" : "â
RAS\n";
return $trouve;
}
public function getInfo(): string {
return parent::getInfo() . " - Chien policier #{$this->matricule}";
}
}
// UTILISATION
echo "=== DĂMONSTRATION HĂRITAGE ===\n\n";
// Création d'animaux
$chien = new Chien("Max", 3, 25, "Labrador");
$chat = new Chat("Felix", 2, 4);
$chienK9 = new ChienPolicier("Rex", 5, 30, "Berger Allemand");
// Méthodes héritées d'Animal
echo "--- Méthodes héritées ---\n";
$chien->vieillir(); // Hérité d'Animal
$chat->vieillir(); // Hérité d'Animal
$chienK9->vieillir(); // Hérité d'Animal via Chien
// Méthodes redéfinies
echo "\n--- Méthodes redéfinies ---\n";
$chien->manger(0.5); // Version Chien
$chat->dormir(); // Version Chat
$chienK9->manger(0.5); // Version Chien (hérité)
// Méthodes spécifiques
echo "\n--- Méthodes spécifiques ---\n";
$chien->aboyer(); // Spécifique à Chien
$chat->miauler(); // Spécifique à Chat
$chienK9->rechercher(); // Spécifique à ChienPolicier
// Informations complĂštes
echo "\n--- Informations ---\n";
echo $chien->getInfo() . "\n";
echo $chat->getInfo() . "\n";
echo $chienK9->getInfo() . "\n";
// Test instanceof
echo "\n--- Tests de type ---\n";
echo "Max est un Animal? " . ($chien instanceof Animal ? "Oui" : "Non") . "\n";
echo "Max est un Chien? " . ($chien instanceof Chien ? "Oui" : "Non") . "\n";
echo "Max est un Chat? " . ($chien instanceof Chat ? "Oui" : "Non") . "\n";
echo "Rex est un ChienPolicier? " . ($chienK9 instanceof ChienPolicier ? "Oui" : "Non") . "\n";
?>
đ Chapitre 7 : Polymorphisme et Liaison Dynamique
7.1 Définition du Polymorphisme
đ Polymorphisme : Du grec âpolyâ (plusieurs) et âmorpheâ (forme). CapacitĂ© dâun objet Ă prendre plusieurs formes.
Types de polymorphisme :
- Surcharge (Overloading) - MĂȘme nom, paramĂštres diffĂ©rents
- Redéfinition (Overriding) - Remplacement de méthode parent
- Polymorphisme dâinterface - ImplĂ©mentation dâinterfaces
7.2 Liaison Dynamique
<?php
declare(strict_types=1);
// INTERFACE : Contrat que les classes doivent respecter
interface Sonore {
public function emettreSon(): string;
}
interface Deplacable {
public function seDeplacer(): void;
public function calculerVitesse(): float;
}
// CLASSE ABSTRAITE de base
abstract class AnimalPolymorphe implements Sonore, Deplacable {
protected string $nom;
protected float $vitesseMax;
public function __construct(string $nom, float $vitesseMax) {
$this->nom = $nom;
$this->vitesseMax = $vitesseMax;
}
// Méthode concrÚte commune
public function presenter(): void {
echo "Je suis {$this->nom}, ";
echo "mon cri: " . $this->emettreSon() . ", ";
echo "ma vitesse: {$this->calculerVitesse()} km/h\n";
}
// Méthodes abstraites à implémenter
abstract public function manger(): void;
}
// IMPLĂMENTATIONS CONCRĂTES
class ChienPolymorphe extends AnimalPolymorphe {
public function __construct(string $nom) {
parent::__construct($nom, 40);
}
public function emettreSon(): string {
return "Wouaf wouaf!";
}
public function seDeplacer(): void {
echo "{$this->nom} court sur ses 4 pattes\n";
}
public function calculerVitesse(): float {
return $this->vitesseMax;
}
public function manger(): void {
echo "{$this->nom} mange des croquettes\n";
}
}
class ChatPolymorphe extends AnimalPolymorphe {
public function __construct(string $nom) {
parent::__construct($nom, 48);
}
public function emettreSon(): string {
return "Miaou!";
}
public function seDeplacer(): void {
echo "{$this->nom} se déplace furtivement\n";
}
public function calculerVitesse(): float {
return $this->vitesseMax * 0.8; // Les chats sont plus lents en moyenne
}
public function manger(): void {
echo "{$this->nom} mange du poisson\n";
}
}
class OiseauPolymorphe extends AnimalPolymorphe {
private float $altitudeVol;
public function __construct(string $nom, float $altitudeVol) {
parent::__construct($nom, 60);
$this->altitudeVol = $altitudeVol;
}
public function emettreSon(): string {
return "Cui cui!";
}
public function seDeplacer(): void {
echo "{$this->nom} vole Ă {$this->altitudeVol}m d'altitude\n";
}
public function calculerVitesse(): float {
return $this->vitesseMax * 1.5; // Plus rapide en vol
}
public function manger(): void {
echo "{$this->nom} picore des graines\n";
}
}
// CLASSE UTILISANT LE POLYMORPHISME
class Zoo {
/** @var AnimalPolymorphe[] */
private array $animaux = [];
public function ajouterAnimal(AnimalPolymorphe $animal): void {
$this->animaux[] = $animal;
}
// Polymorphisme : traite tous les animaux de la mĂȘme façon
public function nourrir(): void {
echo "\n=== HEURE DU REPAS ===\n";
foreach ($this->animaux as $animal) {
$animal->manger(); // Liaison dynamique
}
}
public function faireSpectacle(): void {
echo "\n=== SPECTACLE DU ZOO ===\n";
foreach ($this->animaux as $animal) {
$animal->presenter();
$animal->seDeplacer();
echo "---\n";
}
}
// Polymorphisme avec interface
public function concert(): void {
echo "\n=== CONCERT D'ANIMAUX ===\n";
foreach ($this->animaux as $animal) {
if ($animal instanceof Sonore) { // Vérification d'interface
echo get_class($animal) . ": " . $animal->emettreSon() . "\n";
}
}
}
public function courseDeVitesse(): void {
echo "\n=== COURSE DE VITESSE ===\n";
// Trier par vitesse (polymorphisme)
$animauxTries = $this->animaux;
usort($animauxTries, function($a, $b) {
return $b->calculerVitesse() <=> $a->calculerVitesse();
});
foreach ($animauxTries as $position => $animal) {
echo ($position + 1) . ". " . get_class($animal) .
" - " . $animal->calculerVitesse() . " km/h\n";
}
}
}
// DĂMONSTRATION DU POLYMORPHISME
$zoo = new Zoo();
// Ajout d'animaux de types différents
$zoo->ajouterAnimal(new ChienPolymorphe("Rex"));
$zoo->ajouterAnimal(new ChatPolymorphe("Mimi"));
$zoo->ajouterAnimal(new OiseauPolymorphe("Piou", 100));
$zoo->ajouterAnimal(new ChienPolymorphe("Max"));
// Le zoo traite tous les animaux de maniĂšre polymorphe
$zoo->faireSpectacle();
$zoo->nourrir();
$zoo->concert();
$zoo->courseDeVitesse();
// FONCTION POLYMORPHE
function faireCrier(Sonore $creature): void {
echo "La créature fait: " . $creature->emettreSon() . "\n";
}
echo "\n=== TEST FONCTION POLYMORPHE ===\n";
faireCrier(new ChienPolymorphe("Test"));
faireCrier(new ChatPolymorphe("Test2"));
?>
7.3 Exemple Avancé : SystÚme de Paiement
<?php
declare(strict_types=1);
// INTERFACE pour stratégie de paiement
interface MethodePaiement {
public function payer(float $montant): bool;
public function verifierDisponibilite(float $montant): bool;
public function obtenirFrais(float $montant): float;
}
// CLASSE ABSTRAITE
abstract class Paiement implements MethodePaiement {
protected string $titulaire;
protected float $limite;
public function __construct(string $titulaire, float $limite) {
$this->titulaire = $titulaire;
$this->limite = $limite;
}
public function verifierDisponibilite(float $montant): bool {
return $montant <= $this->limite;
}
// Template Method Pattern
public final function effectuerTransaction(float $montant): bool {
echo "\nđł Tentative de paiement de {$montant}âŹ\n";
// Vérifications
if (!$this->verifierDisponibilite($montant)) {
echo "â Montant supĂ©rieur Ă la limite\n";
return false;
}
// Calcul des frais
$frais = $this->obtenirFrais($montant);
$total = $montant + $frais;
echo "đ Montant: {$montant}⏠+ Frais: {$frais}⏠= Total: {$total}âŹ\n";
// Paiement (liaison dynamique)
return $this->payer($total);
}
}
// IMPLĂMENTATIONS CONCRĂTES
class CarteCredit extends Paiement {
private string $numero;
public function __construct(string $titulaire, string $numero, float $limite = 5000) {
parent::__construct($titulaire, $limite);
$this->numero = substr($numero, -4); // Garder seulement les 4 derniers chiffres
}
public function payer(float $montant): bool {
echo "đł Paiement par carte ****{$this->numero}\n";
echo "â
Transaction approuvée\n";
return true;
}
public function obtenirFrais(float $montant): float {
return $montant * 0.02; // 2% de frais
}
}
class PayPal extends Paiement {
private string $email;
public function __construct(string $titulaire, string $email) {
parent::__construct($titulaire, 10000);
$this->email = $email;
}
public function payer(float $montant): bool {
echo "đ
żïž Paiement PayPal ({$this->email})\n";
echo "đ§ Email de confirmation envoyĂ©\n";
echo "â
Paiement effectué\n";
return true;
}
public function obtenirFrais(float $montant): float {
return $montant > 100 ? 3.0 : 0; // 3⏠de frais si > 100âŹ
}
}
class Virement extends Paiement {
private string $iban;
public function __construct(string $titulaire, string $iban) {
parent::__construct($titulaire, 50000);
$this->iban = $iban;
}
public function payer(float $montant): bool {
echo "đŠ Virement bancaire IBAN: {$this->iban}\n";
echo "ⳠTraitement en 1-2 jours ouvrés\n";
echo "â
Ordre de virement envoyé\n";
return true;
}
public function obtenirFrais(float $montant): float {
return 0; // Pas de frais
}
}
// UTILISATION DU POLYMORPHISME
class Boutique {
private string $nom;
public function __construct(string $nom) {
$this->nom = $nom;
}
// Méthode polymorphe : accepte n'importe quelle méthode de paiement
public function traiterCommande(float $montant, MethodePaiement $methode): void {
echo "\nđïž === {$this->nom} ===\n";
echo "đŠ Commande de {$montant}âŹ\n";
if ($methode->effectuerTransaction($montant)) {
echo "đ Commande confirmĂ©e!\n";
} else {
echo "đ Commande annulĂ©e\n";
}
}
}
// Démonstration
$boutique = new Boutique("TechShop");
// Différentes méthodes de paiement
$carte = new CarteCredit("Jean Dupont", "1234567812345678");
$paypal = new PayPal("Marie Martin", "marie@example.com");
$virement = new Virement("Paul Durand", "FR7612345678901234567890123");
// Polymorphisme en action : mĂȘme mĂ©thode, comportements diffĂ©rents
$boutique->traiterCommande(150, $carte);
$boutique->traiterCommande(250, $paypal);
$boutique->traiterCommande(1500, $virement);
// Test avec limite dépassée
$boutique->traiterCommande(6000, $carte); // Ăchec : limite dĂ©passĂ©e
?>
PrĂȘt Ă passer Ă la suite ?
Vous avez terminĂ© cette leçon sur đ Cours Complet : Programmation OrientĂ©e Objet. Continuez votre apprentissage avec la prochaine leçon ou explorez d'autres formations.