Aujourd'hui, nous explorons les concepts avancés de la Programmation Orientée Objet en PHP : l'héritage, la visibilité, les méthodes statiques, les constantes, les interfaces et les traits.
1. Héritage avec extends
Créer une hiérarchie de classes
<?php
class Personne {
protected $nom;
protected $prenom;
protected $age;
public function __construct($nom, $prenom, $age) {
$this->nom = $nom;
$this->prenom = $prenom;
$this->age = $age;
}
public function sePresenter() {
return "Je m'appelle $this->prenom $this->nom et j'ai $this->age ans.";
}
}
class Etudiant extends Personne {
private $ecole;
private $niveau;
public function __construct($nom, $prenom, $age, $ecole, $niveau) {
parent::__construct($nom, $prenom, $age);
$this->ecole = $ecole;
$this->niveau = $niveau;
}
public function etudier() {
return "$this->prenom étudie en $this->niveau à $this->ecole.";
}
public function sePresenter() {
return parent::sePresenter() . " Je suis étudiant en $this->niveau.";
}
}
$personne = new Personne("Dupont", "Jean", 45);
$etudiant = new Etudiant("Martin", "Marie", 20, "Sorbonne", "Master 2");
echo $personne->sePresenter() . "<br>";
echo $etudiant->sePresenter() . "<br>";
echo $etudiant->etudier();
?>
Résultat :
Je m'appelle Jean Dupont et j'ai 45 ans.
Je m'appelle Marie Martin et j'ai 20 ans. Je suis étudiant en Master 2.
Marie étudie en Master 2 à Sorbonne.
Concepts clés de l'héritage :
- extends : Hériter d'une classe parente
- parent:: : Appeler une méthode de la classe parente
- override : Redéfinir une méthode du parent dans l'enfant
- La classe enfant hérite de TOUTES les propriétés et méthodes publiques/protected du parent
2. Visibilité : public, private, protected
Contrôler l'accès aux propriétés et méthodes
| Visibilité |
Accessible depuis la classe |
Accessible depuis une classe enfant |
Accessible depuis l'extérieur |
| public |
Oui |
Oui |
Oui |
| protected |
Oui |
Oui |
Non |
| private |
Oui |
Non |
Non |
Exemple pratique
<?php
class CompteBancaire {
public $titulaire;
protected $numero;
private $solde;
public function __construct($titulaire, $numero, $soldeInitial) {
$this->titulaire = $titulaire;
$this->numero = $numero;
$this->solde = $soldeInitial;
}
public function getSolde() {
return $this->solde;
}
public function deposer($montant) {
if ($montant > 0) {
$this->solde += $montant;
return "Dépôt de $montant€ effectué. Nouveau solde : " . $this->solde . "€";
}
return "Montant invalide.";
}
public function retirer($montant) {
if ($montant > 0 && $montant <= $this->solde) {
$this->solde -= $montant;
return "Retrait de $montant€ effectué. Nouveau solde : " . $this->solde . "€";
}
return "Solde insuffisant ou montant invalide.";
}
private function verifierSolde() {
return $this->solde >= 0;
}
}
$compte = new CompteBancaire("Jean Dupont", "FR123456", 1000);
echo $compte->titulaire . "<br>";
echo $compte->getSolde() . "<br>";
echo $compte->deposer(500) . "<br>";
?>
Pourquoi utiliser private/protected ?
- Encapsulation : Protéger les données sensibles (solde bancaire)
- Contrôle : Valider les données avant modification
- Maintenance : Changer l'implémentation interne sans casser le code externe
- Sécurité : Empêcher la modification directe de propriétés critiques
3. Méthodes et propriétés static
Membres partagés entre toutes les instances
<?php
class Utilisateur {
public $nom;
private static $compteur = 0;
public function __construct($nom) {
$this->nom = $nom;
self::$compteur++;
}
public static function getNombreUtilisateurs() {
return self::$compteur;
}
public static function validerEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
}
echo "Utilisateurs au départ : " . Utilisateur::getNombreUtilisateurs() . "<br>";
$user1 = new Utilisateur("Jean");
$user2 = new Utilisateur("Marie");
$user3 = new Utilisateur("Paul");
echo "Utilisateurs créés : " . Utilisateur::getNombreUtilisateurs() . "<br>";
if (Utilisateur::validerEmail("test@example.com")) {
echo "Email valide !";
}
?>
Résultat :
Utilisateurs au départ : 0
Utilisateurs créés : 3
Email valide !
Quand utiliser static ?
- Compteurs : Compter les instances créées
- Utilitaires : Fonctions qui ne dépendent pas d'un objet (validation, formatage)
- Configuration : Stocker des valeurs partagées
- Factory methods : Créer des objets de manière spécialisée
4. Constantes de classe
Valeurs immuables au niveau de la classe
<?php
class Configuration {
const VERSION = "1.0.0";
const NOM_APP = "MonSuperSite";
const MAX_UPLOAD_SIZE = 5242880;
public static function afficherInfo() {
echo "Application : " . self::NOM_APP . "<br>";
echo "Version : " . self::VERSION . "<br>";
echo "Taille max upload : " . (self::MAX_UPLOAD_SIZE / 1024 / 1024) . " Mo";
}
}
echo Configuration::VERSION . "<br>";
echo Configuration::NOM_APP . "<br>";
Configuration::afficherInfo();
?>
Exemple : Statuts d'utilisateur
<?php
class Utilisateur {
const STATUT_ACTIF = 1;
const STATUT_INACTIF = 0;
const STATUT_SUSPENDU = 2;
const ROLE_USER = "user";
const ROLE_ADMIN = "admin";
const ROLE_MODERATEUR = "moderateur";
private $nom;
private $statut;
private $role;
public function __construct($nom, $role = self::ROLE_USER) {
$this->nom = $nom;
$this->statut = self::STATUT_ACTIF;
$this->role = $role;
}
public function estActif() {
return $this->statut === self::STATUT_ACTIF;
}
public function estAdmin() {
return $this->role === self::ROLE_ADMIN;
}
}
$user = new Utilisateur("Jean", Utilisateur::ROLE_ADMIN);
if ($user->estAdmin()) {
echo "Accès administrateur accordé.";
}
?>
5. Interfaces
Définir un contrat
<?php
interface Affichable {
public function afficher();
public function afficherResume();
}
class Article implements Affichable {
private $titre;
private $contenu;
public function __construct($titre, $contenu) {
$this->titre = $titre;
$this->contenu = $contenu;
}
public function afficher() {
return "<h2>$this->titre</h2><p>$this->contenu</p>";
}
public function afficherResume() {
return "$this->titre : " . substr($this->contenu, 0, 50) . "...";
}
}
class Produit implements Affichable {
private $nom;
private $prix;
public function __construct($nom, $prix) {
$this->nom = $nom;
$this->prix = $prix;
}
public function afficher() {
return "<h3>$this->nom</h3><p>Prix : $this->prix €</p>";
}
public function afficherResume() {
return "$this->nom ($this->prix €)";
}
}
function afficherElement(Affichable $element) {
echo $element->afficher();
}
$article = new Article("PHP POO", "Apprendre la programmation orientée objet...");
$produit = new Produit("Laptop", 999.99);
afficherElement($article);
afficherElement($produit);
?>
Interfaces vs Classes abstraites :
- Interface : Définit QUOI faire (aucune implémentation)
- Classe abstraite : Définit QUOI et peut définir COMMENT (peut avoir des méthodes implémentées)
- Une classe peut implémenter PLUSIEURS interfaces, mais hériter d'UNE SEULE classe
6. Traits
Réutiliser du code entre classes
<?php
trait Horodatage {
private $dateCreation;
private $dateModification;
public function setDateCreation() {
$this->dateCreation = date("Y-m-d H:i:s");
}
public function setDateModification() {
$this->dateModification = date("Y-m-d H:i:s");
}
public function getDateCreation() {
return $this->dateCreation;
}
}
trait Identifiable {
private $id;
public function setId($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
}
class Article {
use Horodatage, Identifiable;
private $titre;
private $contenu;
public function __construct($id, $titre, $contenu) {
$this->setId($id);
$this->titre = $titre;
$this->contenu = $contenu;
$this->setDateCreation();
}
}
class Utilisateur {
use Horodatage, Identifiable;
private $nom;
public function __construct($id, $nom) {
$this->setId($id);
$this->nom = $nom;
$this->setDateCreation();
}
}
$article = new Article(1, "Mon article", "Contenu...");
echo "Article ID : " . $article->getId() . "<br>";
echo "Créé le : " . $article->getDateCreation();
?>
Quand utiliser les traits ?
- Partager du code entre classes sans héritage
- Éviter la duplication de code
- Ajouter des fonctionnalités transversales (logs, timestamps...)
- Alternative à l'héritage multiple (PHP ne supporte pas l'héritage multiple)
Froggiesplaining :
Objectifs de ce cours :
✅ Maîtriser l'héritage avec extends et parent::
✅ Comprendre les modificateurs de visibilité (public, protected, private)
✅ Utiliser les membres static et les constantes
✅ Implémenter des interfaces pour définir des contrats
✅ Utiliser les traits pour partager du code entre classes
Points clés à retenir :
• Héritage = Etudiant extends Personne (grenouille savante qui hérite des capacités de base)
• public = Accessible partout (ma couleur verte visible par tous)
• protected = Accessible dans la classe et ses enfants (mon ADN familial)
• private = Accessible uniquement dans la classe (mes pensées secrètes)
• static = Partagé par toutes les instances (compteur de grenouilles dans la mare)
• const = Valeurs immuables (COULEUR_DEFAUT = "vert")
• Interface = Contrat définissant QUOI faire (Nageable impose nager())
• Trait = Code réutilisable sans héritage (lunettes portables par tous)
Exercice pratique :
1. Créer une classe CompteBancaire avec propriétés private (solde, titulaire)
2. Ajouter des méthodes public pour accéder/modifier le solde de façon contrôlée
3. Créer une classe CompteEpargne qui extends CompteBancaire
4. Ajouter une constante TAUX_INTERET et une méthode static calculerInterets()
5. Créer une interface Transferable avec méthode transferer()
6. Implémenter l'interface dans CompteBancaire
7. Conseil de Froggie: Utilise private pour protéger les données sensibles comme mon solde bancaire de mouches !