Polar Code 🎭

Command Palette

Search for a command to run...

08
Pièce N°08

Module 8 : La POO - Architecture de l'Ombre

La pluie frappait les vitres du bureau. Sur le tableau noir, des boîtes reliées par des flèches. Des classes. Des objets. La POO, c'était ça : organiser le chaos en entités distinctes. Chacune avec son rôle, ses secrets, ses méthodes. Comme une équipe d'agents. Chacun spécialisé. Chacun avec son propre dossier. En PHP, c'était devenu indispensable. Structurer. Protéger. Hériter.

Classes et objets Une classe, c'est le plan. L'objet, c'est l'agent sur le terrain. Le plan définit ce qu'il peut faire. L'agent exécute.

<?php
// agent.php
echo "<div style='font-family: monospace; background: #111; color: #ccc; padding: 20px;'>";
echo "<h3 style='color: #8b0000;'>▪ CLASSES ET OBJETS ▪</h3>";

// Une classe : le plan d'un agent
class Agent {
    // Propriétés (données)
    public $nom;
    public $code;
    public $specialite;
    
    // Méthode (comportement)
    public function sePresenter() {
        return "Agent $this->nom, code $this->code. Spécialité : $this->specialite.";
    }
}

// Création d'objets (instances)
$agent1 = new Agent();
$agent1->nom = "Marlowe";
$agent1->code = "47";
$agent1->specialite = "Infiltration";

$agent2 = new Agent();
$agent2->nom = "Sterling";
$agent2->code = "11";
$agent2->specialite = "Interrogatoire";

echo "<div style='background: #1a1a1a; padding: 15px; margin: 10px 0; border-left: 3px solid #444;'>";
echo "<h4>▪ AGENTS SUR LE TERRAIN ▪</h4>";
echo "<p>" . $agent1->sePresenter() . "</p>";
echo "<p>" . $agent2->sePresenter() . "</p>";
echo "</div>";

// Vérification
echo "<pre style='background: #000; padding: 10px; color: #888;'>";
var_dump($agent1);
echo "</pre>";
echo "</div>";
?>

Propriétés et méthodes Les données et les actions. Ce que l'objet sait, et ce qu'il peut faire.

<?php
// proprietes_methodes.php
class Contrebandier {
    // Propriétés (état)
    private $nom;
    private $marchandises = [];
    private $capital = 0;
    private $risque = 0;
    
    // Méthodes (comportements)
    public function __construct($nom, $capitalInitial = 1000) {
        $this->nom = $nom;
        $this->capital = $capitalInitial;
    }
    
    public function acheter($produit, $quantite, $prix) {
        $cout = $quantite * $prix;
        if ($this->capital >= $cout) {
            $this->capital -= $cout;
            $this->marchandises[] = [
                'produit' => $produit,
                'quantite' => $quantite,
                'prix_achat' => $prix
            ];
            $this->risque += $quantite * 5; // Risque accru
            return "Achat réussi : $quantite x $produit";
        }
        return "Fonds insuffisants.";
    }
    
    public function vendre($index, $prixVente) {
        if (isset($this->marchandises[$index])) {
            $marchandise = $this->marchandises[$index];
            $profit = $marchandise['quantite'] * ($prixVente - $marchandise['prix_achat']);
            $this->capital += $marchandise['quantite'] * $prixVente;
            unset($this->marchandises[$index]);
            $this->risque -= $marchandise['quantite'] * 3;
            return "Vente : profit de $profit €";
        }
        return "Marchandise introuvable.";
    }
    
    public function getStatut() {
        return [
            'nom' => $this->nom,
            'capital' => $this->capital,
            'marchandises' => count($this->marchandises),
            'risque' => $this->risque
        ];
    }
}

// Utilisation
$carlo = new Contrebandier("Carlo", 5000);

echo "<div style='font-family: monospace; background: #1a1a1a; color: #ccc; padding: 20px;'>";
echo "<h4 style='color: #8b0000;'>▪ OPÉRATIONS ILLICITES ▪</h4>";

echo "<p>" . $carlo->acheter("Cigares", 50, 20) . "</p>";
echo "<p>" . $carlo->acheter("Montres", 10, 150) . "</p>";
echo "<p>" . $carlo->vendre(0, 35) . "</p>";

$statut = $carlo->getStatut();
echo "<div style='background: #111; padding: 15px; margin: 15px 0;'>";
echo "<strong>STATUT DE " . $statut['nom'] . "</strong><br>";
echo "Capital : " . $statut['capital'] . " €<br>";
echo "Marchandises en stock : " . $statut['marchandises'] . "<br>";
echo "Niveau de risque : " . $statut['risque'];
echo "</div>";
echo "</div>";
?>

Constructeurs et destructeurs La naissance et la mort de l'objet. Les premiers ordres. Les dernières volontés.

<?php
// vie_objet.php
class OperationSecrete {
    private $code;
    private $dateDebut;
    private $agents = [];
    private $active = false;
    private $fichierLog;
    
    // Constructeur : naissance de l'opération
    public function __construct($code, $dateDebut) {
        $this->code = $code;
        $this->dateDebut = $dateDebut;
        $this->fichierLog = "logs/operation_$code.log";
        
        // Initialisation
        file_put_contents($this->fichierLog, 
            "=== OPÉRATION $code INITIÉE ===\n" .
            "Date: $dateDebut\n" .
            "Statut: EN PRÉPARATION\n\n"
        );
        
        echo "<p style='color: #4caf50;'>▪ OPÉRATION $code INITIALISÉE ▪</p>";
    }
    
    // Destructeur : fin de l'opération
    public function __destruct() {
        $dateFin = date('Y-m-d H:i:s');
        file_put_contents($this->fichierLog, 
            "\n=== OPÉRATION $this->code TERMINÉE ===\n" .
            "Date: $dateFin\n" .
            "Agents impliqués: " . count($this->agents) . "\n" .
            "Statut: ARCHIVÉE\n",
            FILE_APPEND
        );
        
        echo "<p style='color: #ff5555;'>▪ OPÉRATION $this->code ARCHIVÉE ▪</p>";
    }
    
    public function activer() {
        $this->active = true;
        file_put_contents($this->fichierLog, 
            date('Y-m-d H:i:s') . " | OPÉRATION ACTIVÉE\n",
            FILE_APPEND
        );
    }
    
    public function ajouterAgent($agent) {
        $this->agents[] = $agent;
    }
}

echo "<div style='font-family: monospace; background: #111; color: #ccc; padding: 20px;'>";
echo "<h4 style='color: #8b0000;'>▪ CYCLE DE VIE D'UNE OPÉRATION ▪</h4>";

// L'objet naît
$op = new OperationSecrete("NIGHTFALL", date('Y-m-d H:i:s'));
$op->ajouterAgent("Marlowe");
$op->ajouterAgent("Sterling");
$op->activer();

// Simulation
echo "<p>Opération en cours...</p>";
echo "<p>Exécution des missions...</p>";

// L'objet meurt à la fin du script
// Le destructeur s'exécute automatiquement
echo "</div>";
?>

Encapsulation, héritage, visibilité Protéger. Étendre. Contrôler l'accès.

<?php
// encapsulation_heritage.php

// CLASSE MÈRE
class Personne {
    // Visibilité : public, protected, private
    protected $nom;          // Accessible dans la classe et les enfants
    private $dateNaissance;  // Accessible uniquement ici
    public $code;            // Accessible partout
    
    public function __construct($nom, $dateNaissance, $code) {
        $this->nom = $nom;
        $this->dateNaissance = $dateNaissance;
        $this->code = $code;
    }
    
    // Getters pour accéder aux propriétés privées/protégées
    public function getNom() {
        return $this->nom;
    }
    
    public function getAge() {
        $now = new DateTime();
        $naissance = new DateTime($this->dateNaissance);
        $interval = $now->diff($naissance);
        return $interval->y;
    }
    
    // Méthode finale (ne peut être surchargée)
    final public function identiteComplete() {
        return $this->nom . " (" . $this->code . ")";
    }
}

// HÉRITAGE
class AgentSpecial extends Personne {
    private $niveauAcces;
    private $missions = [];
    
    public function __construct($nom, $dateNaissance, $code, $niveauAcces) {
        parent::__construct($nom, $dateNaissance, $code); // Appel au parent
        $this->niveauAcces = $niveauAcces;
    }
    
    // Polymorphisme : méthode spécifique
    public function ajouterMission($mission) {
        $this->missions[] = $mission;
    }
    
    public function getMissions() {
        return $this->missions;
    }
    
    // Surcharge de méthode (mais pas getAge() car non définie ici)
    public function getStatut() {
        return [
            'agent' => $this->getNom(),
            'code' => $this->code,
            'niveau' => $this->niveauAcces,
            'missions' => count($this->missions),
            'age' => $this->getAge()
        ];
    }
}

echo "<div style='font-family: monospace; background: #111; color: #ccc; padding: 20px;'>";
echo "<h4 style='color: #8b0000;'>▪ ENCAPSULATION ET HÉRITAGE ▪</h4>";

// Personne normale
$civil = new Personne("Dupont", "1985-04-12", "CIV001");
echo "<div style='background: #1a1a1a; padding: 15px; margin: 10px 0;'>";
echo "<strong>PERSONNE CIVILE</strong><br>";
echo "Nom via getter : " . $civil->getNom() . "<br>";
echo "Âge : " . $civil->getAge() . " ans<br>";
echo "Code public : " . $civil->code . "<br>";
// echo $civil->nom; // ERREUR : protected
// echo $civil->dateNaissance; // ERREUR : private
echo "</div>";

// Agent spécial
$agent = new AgentSpecial("Marlowe", "1978-11-23", "AGENT47", 9);
$agent->ajouterMission("Infiltration casino");
$agent->ajouterMission("Récupération documents");

echo "<div style='background: #1a1a1a; padding: 15px; margin: 10px 0;'>";
echo "<strong>AGENT SPÉCIAL</strong><br>";
$statut = $agent->getStatut();
echo "Identité : " . $agent->identiteComplete() . "<br>";
echo "Niveau d'accès : " . $statut['niveau'] . "<br>";
echo "Missions actives : " . $statut['missions'] . "<br>";
echo "Âge : " . $statut['age'] . " ans<br>";
echo "</div>";

// Vérification de l'héritage
echo "<pre style='background: #000; padding: 10px; color: #888;'>";
echo "L'agent est une Personne ? " . (($agent instanceof Personne) ? "OUI" : "NON") . "\n";
echo "L'agent est un AgentSpecial ? " . (($agent instanceof AgentSpecial) ? "OUI" : "NON") . "\n";
echo "Le civil est un AgentSpecial ? " . (($civil instanceof AgentSpecial) ? "OUI" : "NON");
echo "</pre>";
echo "</div>";
?>

Introduction aux interfaces et traits Des contrats. Des morceaux de code réutilisables.

<?php
// interfaces_traits.php

// INTERFACE : un contrat
interface Arme {
    public function tirer();
    public function recharger();
    public function getMunitions();
}

// TRAIT : code réutilisable
trait Discret {
    private $silencieux = false;
    
    public function activerSilencieux() {
        $this->silencieux = true;
        return "Silencieux activé.";
    }
    
    public function desactiverSilencieux() {
        $this->silencieux = false;
        return "Silencieux désactivé.";
    }
    
    public function estSilencieux() {
        return $this->silencieux;
    }
}

// CLASSE avec interface et trait
class Pistolet implements Arme {
    use Discret; // Inclusion du trait
    
    private $munitions;
    private $modele;
    
    public function __construct($modele, $munitions = 12) {
        $this->modele = $modele;
        $this->munitions = $munitions;
    }
    
    // Implémentation des méthodes de l'interface
    public function tirer() {
        if ($this->munitions > 0) {
            $this->munitions--;
            $bruit = $this->estSilencieux() ? "Pffft..." : "BANG!";
            return "Tir effectué avec le $this->modele. $bruit";
        }
        return "Clic... Plus de munitions.";
    }
    
    public function recharger() {
        $this->munitions = 12;
        return "Pistolet rechargé.";
    }
    
    public function getMunitions() {
        return $this->munitions;
    }
    
    // Méthode spécifique
    public function getModele() {
        return $this->modele;
    }
}

// AUTRE CLASSE avec la même interface
class Fusil implements Arme {
    private $munitions = 30;
    
    public function tirer() {
        if ($this->munitions > 0) {
            $this->munitions -= 3; // Tire par rafales
            return "BURRRRT! Rafale de 3 balles.";
        }
        return "Chargeur vide.";
    }
    
    public function recharger() {
        $this->munitions = 30;
        return "Fusil rechargé.";
    }
    
    public function getMunitions() {
        return $this->munitions;
    }
}

echo "<div style='font-family: monospace; background: #111; color: #ccc; padding: 20px;'>";
echo "<h4 style='color: #8b0000;'>▪ INTERFACES ET TRAITS ▪</h4>";

// Utilisation
$glock = new Pistolet("Glock 17");
$ak47 = new Fusil();

echo "<div style='background: #1a1a1a; padding: 15px; margin: 10px 0;'>";
echo "<strong>ARMES DISPONIBLES</strong><br><br>";

echo "<strong>Pistolet :</strong><br>";
echo $glock->activerSilencieux() . "<br>";
echo $glock->tirer() . "<br>";
echo $glock->tirer() . "<br>";
echo "Munitions restantes : " . $glock->getMunitions() . "<br>";
echo "Modèle : " . $glock->getModele() . "<br><br>";

echo "<strong>Fusil :</strong><br>";
echo $ak47->tirer() . "<br>";
echo "Munitions restantes : " . $ak47->getMunitions() . "<br><br>";

// Polymorphisme via l'interface
function verifierArme(Arme $arme) {
    echo "<div style='background: #222; padding: 10px; margin: 10px 0;'>";
    echo "▪ VÉRIFICATION D'ARME ▪<br>";
    echo "Munitions : " . $arme->getMunitions() . "<br>";
    echo "Test de tir : " . $arme->tirer() . "<br>";
    echo "Type : " . get_class($arme);
    echo "</div>";
}

verifierArme($glock);
verifierArme($ak47);

echo "</div>";

// Vérification
echo "<pre style='background: #000; padding: 10px; color: #888;'>";
echo "Le Glock est une Arme ? " . (($glock instanceof Arme) ? "OUI" : "NON") . "\n";
echo "Le Glock utilise le trait Discret ? " . (method_exists($glock, 'estSilencieux') ? "OUI" : "NON");
echo "</pre>";
echo "</div>";
?>

Je me renversai dans le fauteuil, le cigare éteint entre les doigts. La POO. Une architecture. Un système où chaque entité avait son rôle, ses données privées, ses méthodes publiques. L'encapsulation protégeait les secrets. L'héritage créait des lignées. Les interfaces imposaient des contrats. Les traits partageaient des comportements. C'était plus qu'une façon de coder. C'était une façon de penser. D'organiser le chaos en unités discrètes, autonomes, spécialisées. Comme une équipe d'agents. Chacun avec son dossier. Chacun avec ses missions. Mais tous faisant partie du même réseau. Du même système.