PHP - MySQL [Retour au menu]
Les classes

Création, instanciation, méthodes, héritage, surcharge

Création d'une classe très simple : Bistrot

Une classe n'est rien d'autre qu'un ensemble de fonctions et de variables. Nous allons créer une Classe Bistrot, qui sera composée de 2 fonctions simples : ServirABoire et MettreLaTable. Nous "ouvrirons" ensuite un nouveau bistrot : $CafeDesAmis = new Bistrot;, et depuis cette "variable composée", nous allons appeler la fonction ServirABoire et MettreLaTable :  $CafeDesAmis->ServirABoire(); et $CafeDesAmis->MettreLaTable();.

class Bistrot
  {
  function ServirABoire()
    {
    echo "Je sers à boire";
    }
  function MettreLaTable()
    {
    echo "Je met la table";
    }
  }  
$CafeDesAmis = new Bistrot;
$CafeDesAmis->ServirABoire();
$CafeDesAmis->MettreLaTable();

Plusieurs instances d'une même classe

Lors de la ligne $CafeDesAmis = new Bistrot;, nous disons que nous instancions la classe Bistrot : nous créons une instance de cette classe. Nous pouvons avoir plusieurs instances d'une même classe :

class Bistrot
  {
  function ServirABoire()
    {
    echo "Je sers à boire";
    }
  }  
$CafeDesAmis = new Bistrot;
$AuSoleilLevant = new Bistrot;
$CafeDesAmis->ServirABoire();
$AuSoleilLevant->ServirABoire();

Utilisation d'une variable dans une classe

class Bistrot
  {
  var $NombreClient;
  }
$MonCafe = new Bistrot;
$MonCafe->$NombreClient++;
echo $MonCafe->$NombreClient;

Permanence des variables

L'intérêt des classes par rapport aux fonctions simples, est que les variables gardent automatiquement leurs valeurs dans les instances respectives. Je m'explique par un exemple simple :

class Bistrot
  {
  var $NomBreClient;
  }
$CafeDeLaGare = new Bistrot;
$SoleilLevant = new Bistrot;
$CafeDeLaGare->$NombreClient+=5;
$SoleilLevant->$NombreClient+=2;
$CafeDeLaGare->$NombreClient++;
echo $CafeDeLaGare->$NombreClient; // Affiche 6
echo $SoleilLevant->$NombreClient; // Affiche 2

Utilisation de fonctions pour l'accès aux variables

L'usage veut qu'un passe plutôt par une fonction que directement par les variables. Par exemple, on pourrait imaginer une fonction pour ajouter un client, et pour retirer un client :

class Bistrot
  {
  var $NombreClient;
  function AjouteClient()
    {
    $NombreClient++
    }

  function EnleveClient()
    {
    $NombreClient--
    }

  }
$CafeDeLaGare = new Bistrot;
$CafeDeLaGare->AjouteClient();
$CafeDeLaGare->AjouteClient();
$CafeDeLaGare->EnleveClient();
echo $CafeDeLaGare->$NombreClient // devrait afficher 1

... Mais en fait n'affiche rien du tout (comme si $NombreClient ne valait rien). En fait, les $NombreClient utilisés dans les 2 fonctions sont considérées comme 2 variables locales distinctes $NombreClient et $NombreClient, bien qu'elles aient le même nom ! Ce qui fait que la variable globale $NombreClient de la classe n'est jamais incrémentée !

A contrario, l'exemple précédant celui-ci fonctionnait très bien, puisqu'on accédait directement à la variable globale de la classe $NombreClient

Utilisation de $this->

Pour préciser que nous désirons bien utiliser la variable globale $NombreClient, nous allons utiliser le mot-clé this, qui veut dire "Celle ci", "la variable globale de cette classe", comme ceci :

class Bistrot
  {
  var $NombreClient;
  function AjouteClient()
    {
    $this->$NombreClient++;
    }

  function EnleveClient()
    {
    $this->$NombreClient--;
    }

  }
$CafeDeLaGare = new Bistrot;
$CafeDeLaGare->AjouteClient();
$CafeDeLaGare->AjouteClient();

$CafeDeLaGare->EnleveClient();
echo $CafeDeLaGare->$NombreClient // Affiche vraiment 1 cette fois

Le constructeur

Le constructeur est simplement une fonction qui possède le même nom que la classe elle-même. Le constructeur prend en quelque sorte la responsabilité de l'initialisatioon de la classe. Par exemple, admettons que d'entrée, le nombre de clients est = à 5, nous aurions une fonction Bistrot dans la classe Bistrot. Cette fonction est automatiquement appelée lors de l'appel à New Bistrot :

class Bistrot
  {
  var $NombreClient;
  function Bistrot()
    {
    $this->$NombreClient = 5;
    }

  }
$CafeDeLaGare = new Bistrot; // Et appel implicite à Bistrot()
echo $CafeDeLaGare->$NombreClient // Affiche 5

L'héritage avec extends

Il est très possible de définir une classe, avec ses propres variables et fonctions, et ensuite constater qu'on a besoin d'une classe un peu similaire, mais avec des trucs en plus. Dans l'exemple qui suit, nous avons une classe Bistrot, et nous avons fait hérité les variables et fonctions (appelées méthodes dans le contexte d'une classe) à une deuxième classe que nous appellerons Restaurant :

class Bistrot
  {
  function JaiSoif()
    {
    echo "Vous désirez boire un verre";
    }
  }

class Restaurant extends Bistrot
  {
  function JaiFaim()
    {
    echo "Vous désirez le plat du jour";
    }
  }

$CafeDeLaGare = new Bistrot;
$ChezLucullus = new Restaurant;
$CafeDeLaGare->JaiSoif();
$ChezLucullus->JaiSoif();
$ChezLucullus->JaiFaim();

$CafeDeLaGare->JaiFaim(); // ERREUR, évidemment !

Avec PHP, il n'est pas possible de créer une classe dérivée de 2 classes-mères différentes. Par exemple, si nous avons une classe Bistrot et une classe BoiteDeNuit, il n'est pas possible d'écrire un truc du style :
Class CentreDeLoisirs extends Bistrot, BoiteDeNuit !

Il est possible d'hériter d'une classe elle-même héritée d'une autre classe :

class Bistrot
  {
  function JaiSoif()
    {
    echo "Vous désirez boire un verre";
    }
  }
class Restaurant extends Bistrot
  {
  function JaiFaim()
    {
    echo "Vous désirez le plat du jour";
    }
  }

class Hotel extends Restaurant
  {
  function JaiSommeil()
    {
    echo "Vous désirez dormir";
    }
  }

$LeBonRepos = new Hotel;
$LeBonRepos->JaiFaim();
$LeBonRepos->JaiSoif();
$LeBonRepos->JaiSommeil();

Des fonctions identiques dans des classes différentes

Que se passe-t-il si une classe possède une fonction de même nom que la classe parente ? Une erreur ? Pas du tout ! PHP s'en sort très bien, comme ceci :

class Bistrot
  {
  function JaiSoif()
    {
    echo "Tiens, vla une bière !";
    }

  }
class Restaurant extends Bistrot
  {
  function JaiSoif()
    {
    echo "Voici un petit apéritif";
    }

  function JaiFaim()
    {
    echo "Voici votre plat du jour"
    }
  }

$ChezLucullus = new Restaurant;
$CafeDeLaGare = new Bistrot;
$ChezLucullus->JaiSoif(); // petit apéritif
$CafeDeLaGare->JaiSoif(); // une bière

Bien entendu, l'usage des variables suit la même règle.

Cohabitation de la notion d'héritage et de constructeurs

Nous avons vu qu'une fonction qui porte le nom de la classe est automatiquement exécutée lors de l'instanciation de la classe en question avec new. Bien. Ensuite, nous avons vu que nous pouvons créer de nouvelles classes en les dérivant de classes parentes en utilisant l'héritage et le mot-clé extends. Parfait. Considérons maintenant cet exemple :

class Bistrot
  {
  function Bistrot()
    {
    echo "Je construit le Bistrot";
    }
  }
class Restaurant extends Bistrot
  {
  }
$ChezLucullus = new Restaurant;

Pensez-vous que lors de l'instanciation $ChezLucullus = new Restaurant;, le constructeur function Bistrot() sera exécuté ?

La réponse est OUI avec PHP4 et NON avec PHP3. Fallait le savoir !

Et un exemple un peu tordu pour terminer

Dans l'exemple qui suit, nous allons définir 2 classes : Une classe Bistrot et une classe Restaurant. La classe Restaurant ne contient rien : elle est juste héritée de Bistrot, c'est tout. La classe Bistrot, par contre, a une particularité un peu tordue : Elle a un constructeur Bistrot() qui sera évidemment appelé dès l'instanciation d'une classe Bistrot, on est d'accord. MAIS, et c'est là qu'il faut suivre, cette classe possède une fonction Restaurant : OK, pourquoi pas... Mais il se trouve que d'après son nom, si cette fonction s'était trouvée dans la classe Restaurant, elle aurait été le constructeur de cette dernière... Je vous propose donc l'exemple suivant : comment pensez-vous que PHP va réagir ?

class Bistrot
  {
  function Bistrot()
    {
    echo "Je construis le Bistrot";
    }
  function Restaurant()
    {
    echo "Je construis le restaurant";
    }

  }
class Restaurant extends Bistrot
  {
  }
$ChezLucullus = new Restaurant;

En fait, lors de l'instanciation de $CafeDeLaGare = new Bistrot;, le constructeur function Bistrot() va s'exécuter automatiquement. Et lors de l'instanciation $ChezLucullus = new Restaurant;, il va automatiquement exécuter function Restaurant()de la classe Bistrot, qu'il va considérer comme son constructeur !!!

Bon, comme on pourrait s'y attendre, le cas suivant n'exécute QUE le constructeur de la classe Restaurant :

class Bistrot
  {
  function Restaurant() // n'est pas exécutée
    {
    echo "Je construis le restaurant depuis le Bistrot";
    }
  }

class Restaurant extends Bistrot
  {
  function Restaurant ()
    {
    echo "Je construit le restaurant depuis le restaurant";
    }
  }

$ChezLucullus = new Restaurant; // "Je construit le restaurant depuis le restaurant"

J'utilise PHP4, et c'est effectivement le résultat que j'obtiens. Etrangement d'ailleurs, car dans l'aide de PHP, il est très nettement écrit : "'Un constructeur est une classe de même nom, définit dans la classe elle-même", ce qui veut bien dire que normalement, un constructeur ne peut pas se trouver dans la classe parente, me semble-t-il ...

Comment depuis une classe dérivée, appeler une méthode de la classe parente

Tout simplement en faisant ceci :

$this->nom_de_la_methode_parente();

---