Hébergement du site en PHP et Mysql par WDMédia-hébergement
Vous aussi adpotez les éléPHPants de Vincent Pontier !  
CONCOURS
 
 
PLUS DE PHP
 
 
PLUS DE JAVASCRIPT
 
COMMENT CA MARCHE
 
 
EXPLIQUE-MOI
 
 
NEWS LETTER
 

 
PARTENAIRES
 
Découvrez scriptsphp.org
Découvrez phpteam.net
Tout sur les expressions régulières
IE sucks :-)
 
DESIGN DU SITE
 
Classes et objets II
La sortie de PHP5 va amener à revoir ce tuto de Nikoh, qui reste valable pour PHP4.


Partie 2: L'héritage.

    Après une introduction sur les classes et une étude d'exemple plutôt gastronomique, un thème essentiel doit maintenant être abordé: l'héritage (rassurez-vous, il n'y aura pas de morts...). Ici encore, le PHP permet de faire un certain nombre de choses bien pratiques, même si l'on est encore loin des possibilités offertes par d'autres langages.
    Quant au concept se cachant derrière le terme de "polymorphisme", mieux vaut attendre d'avoir traité en détail l'héritage avant d'en parler...

    Prérequis: Première partie du tutoriel, tutoriel sur include ("Débutez!" n°17 sur les "Pseudo-Frames"), visibilité des variables, les fonctions en PHP
I) Qu'est ce que c'est ?

    L'héritage permet de spécialiser le code et/ou réutiliser du code déjà existant pour l'adapter à ses besoins. En d'autres termes, il permet, à partir d'une classe déjà existante, d'en créer une nouvelle qui reprendra ses caractéristiques ce qui nous permettra de les adapter à d'autres besoins sans modifier la classe de base. Comme toujours, tout ceci peut paraître abstrait, passons donc à un premier exemple:

    Imaginons que vous ayez une classe "CompactDisc" permettant de gérer votre stock de CD. Elle pourrait être définie de la manière suivante:
    Classe: "CompactDisc"
    Variables membres:
    $titre, $dateAchat
    Fonctions membres:
    afficherTitre()
    afficherDateAchat()

    Remarque: Pour simplifier, je n'ai pas donné le code de cette classe, mais juste les éléments qui la composent.

    Admettons que c'est un peu basique et que cette classe ne fait pas grand chose...Mais elle a tout de même l'immense avantage d'être valable quel que soit le type de CD.
    Maintenant, si l'on veut gérer des CD audio, il faudrait ajouter certains éléments (genre musical par exemple): c'est la spécialisation. Pour cela, nul besoin de modifier directement cette classe (elle pourra toujours reservir), il nous suffit d'en créer une nouvelle qui héritera de toutes les caractéristiques de la classe de base "CompactDisc".
    Pour cela, on défini la classe CDAudio:

    Classe: "CDAudio"
    Variables membres:
    $genreMusical
    Fonctions membres:
    afficherGenreMusical()

    Il ne reste plus qu'à indiquer à PHP que la classe CDAudio hérite de la classe CompactDisc pour que toutes les variables et fonctions membres de CompactDisc soit "données" à CDAudio pour arriver au résultat suivant: (en rouge sont indiqués les éléments hérités.)

    Classe: "CDAudio" hérite de "CompactDisc"
    Variables membres:
    $genreMusical, $titre, $dateAchat
    Fonctions membres:
    afficherGenreMusical()
    afficherTitre()
    afficherDateAchat()

    Et c'est en créant un objet de type CDAudio qu'on obtiendra le résultat voulu...A partir de là, on pourrai définir des classes héritant également de CompactDisc (CDROMLogiciel, CDROMJeu, etc...) mais aussi des classes qui héritent de CDAudio (ex: CDAudioSingle) et qui hériteront donc également de CompactDisc.

    Toutes ces notions d'héritage peuvent être representées sur un diagramme (simplifié):

II) Mise en oeuvre de l'héritage
    a) Syntaxe

    
    class CDAudio extends CompactDisc {
    
    // ...
    }

    Voila tout simplement la syntaxe à utiliser. Ici, la classe CDAudio hérite de la classe CompactDisc.

    Un peu de vocabulaire:

    • On dit que CDAudio hérite de CompactDisc
    • On dit que CompactDisc est la classe de base de CDAudio
    • On dit que CDAudio est un ("is a" en anglais) CompactDisc (terme employé pour le polymorphisme)

    Attention : L'héritage multiple est impossible en PHP. En d'autres termes, CDAudio peut hériter de CompactDisc mais pas de CompactDisc ET de Musique simultanément.
    Bien sur, le contraire est possible (comme on l'a vu précedemment): une classe peut servir de base à plusieurs classes (ex: CDAudio et CDROMLogiciel héritent de CompactDisc)

    Notez que l'impossibilité de faire de l'héritage multiple peut poser problème mais cela permet d'éviter de nombreuses confusions.

    b) Exemple

    Appliquons tout ceci aux classes CompactDisc et CDAudio. Pour cela, nous allons mettre en pratique un conseil de premier tutoriel: un fichier PHP par classe.

    Fichier "CompactDisc.class.php"

    
    <?php
    
    class CompactDisc {
    var
    $titre, $dateAchat;

    function
    afficherTitre() {
    echo
    "<BR>Le titre est: ".$this->titre;
    }

    function
    afficherDateAchat() {
    echo
    "<BR>CD acheté le: ".$this->dateAchat;
    }
    }
    ?>

    Fichier "CDAudio.class.php"

    
    <?php
    
    class CDAudio extends CompactDisc {
    var
    $genreMusical ;

    function
    afficherGenreMusical() {
    echo
    "<BR>Le genre musical est: ".$this->genreMusical;
    }
    }
    ?>

    Fichier "index.php"

    
    <?php
    
    include ("CompactDisc.class.php");
    include (
    "CDAudio.class.php");

    $cd = new CDAudio();
    $cd->titre = "Rock'n PHP";
    $cd->dateAchat = "25/12/2001";
    $cd->genreMusical = "Rock";

    $cd->afficherTitre();
    $cd->afficherDateAchat();
    $cd->afficherGenreMusical();
    ?>

III) Héritage des constructeurs

    Les comportements sont diférents selon PHP3 ou PHP4. On ne parlerai ici que de PHP4 si free.fr ne l'utilisaient pas, mais comme vous êtes nombreux à héberger vos pages chez eux...
    Dans tous les cas, on a vu qu'une classe pouvait posséder un constructeur, appellé à l'initialisation. Voyons ce qu'il se passe dans le cas de l'héritage.

    a) Sous PHP 4 (et surement les versions suivantes)

    Règle n°1: "Si une classe n'a pas de constructeur, le constructeur de la classe de base est appellé (s'il existe)".

    Cette règle est assez claire mais impose tout de même de faire attention. Regardez l'exemple suivant:
    
    class Pere {
    
    var
    $nombreEnfants;

    // constructeur:
    function Pere ($n) {
    $this->nombreEnfants = $n;
    }
    }

    class
    Fils extends Pere {
    var
    $nom;
    }

    Pour créer un objet de type "Fils" et sachant que la classe "Fils" ne possède pas de constructeur, vous seriez peut être tenté par la syntaxe suivante:
    $objet = new Fils();
    Sachez que cela ne marchera pas, car en vertu de la règle n°1, PHP va appeller le constructeur de la classe de base puisqu'aucun constructeur n'existe dans la classe "Fils". Or le constructeur de la classe de base prend un paramètre qu'il est obligatoire de spécifier:
    $objet = new Fils(1); // initialise la variable memnbre $nombreEnfants de la classe "Fils" (hérité de "Pere") à la valeur 1 via le constructeur de la classe "Pere".
    Je vous accorde que ce comportement peut sembler légèrement dérountant, mais en y réfléchissant bien, il n'y a pas vraiment d'autre solution logique...

    Règle n°2: "Un constructeur est une fonction portant le même nom que la classe dans laquelle elle est définie".
    Attention: cette règle ne fonctionne pas correctement malgré ce qui est annoncé dans la documentation.
    Pour le moment, le comportement de PHP4 (au moins jusqu'à 4.0.6) est le même que PHP3 (cf paragraphe suivant).
    Rapport de Bug PHP

    Vous connaissiez déjà une partie de cette règle depuis le tutoriel précédent. Mais, là encore, il faut être vigilant:
    
    class Pere {
    
    var
    $nombreEnfants;

    function
    Fils() {
    $this->nombreEnfants++;
    }
    }

    class
    Fils extends Pere {
    var
    $nom;
    }

    Si l'on considère ces deux classes de manière indépendante, il n'y a pas de constructeur. Néanmoins, par le jeu de l'héritage, la fonction membre Fils() de la classe de base "Pere" se trouvera disponible dans la classe "Fils". On a vu jusqu'à présent qu'une fonction membre est un constructeur si elle porte le même nom que la classe dans laquelle elle est. Ceci n'est pas valable si la fonction est héritée. Ainsi, la classe "Fils" n'aura pas de constructeur mais possèdera une fonction membre héritée nommée Fils().

    b) Sous PHP 3

    Seule et unique règle: "Un constructeur est une fonction portant le même nom que la classe dans laquelle il est appellé, même si la définition de ce constructeur n'a pas été défini dans cette classe."

    Ainsi, si une classe n'a pas de constructeur, aucun constructeur n'est appellé, pas même celui de sa classe de base s'il existe.
    Dans l'exemple suivant, la fonction membre Fils() apparait dans la classe "Fils" par héritage et devient ainsi un constructeur de la classe "Fils".
    
    class Pere {
    
    var
    $nombreEnfants;

    function
    Fils() {
    $this->nombreEnfants++;
    }
    }

    class
    Fils extends Pere {
    var
    $nom;
    }

    c) Propagation des appels au constructeur

    En PHP4, on a vu que s'il n'y a pas de constructeur dans une classe, celui de la classe de base est appellé. Par contre, si un constructeur existe, celui de la classe de base ne sera pas automatiquement appellé, vous devrez donc (si nécessaire) appeller vous même le constructeur de la classe de base.
    En PHP3, quoiqu'il arrive, vous devez effectuer tous les appels aux constructeurs de manière manuelle.

IV) Redéfinition de fonctions membres et mot clé "parent"

    L'héritage permet également de redéfinir des fonctions membres. Le but majeur est bien sur d'adapter une classe à ses besoins en modifiant certaines de ses caractéristiques.

    Le mot clé "parent" permet quant à lui d'accéder à partir d'une classe aux fonctions et variables membres de la classe de base.

    Appliquons ces deux concepts à l'exemple de "CDAudio" et d'une nouvelle classe "CDAudioSingle" (héritant de "CDAudio" qui elle même hérite de "CompactDisc"). Le but des modifications que nous allons faire est changer le comportement de la fonction membre afficherGenreMusical() de la classe "CDAudio" pour que dans la classe "CDAudioSingle" elle ajoute à l'affichage la ligne:
      Ceci est un single.

    Ce qui donne: (les classes "CompactDisc" et "CDAudio" étant inchangées)
    Fichier "CDAudioSingle.class.php"

    
    <?php
    
    class CDAudioSingle extends CDAudio {

    function
    afficherGenreMusical() {
    echo
    "<BR>Ceci est un single.";
    parent::afficherGenreMusical();
    }
    }
    ?>

    Fichier "index.php"

    
    <?php
    
    include ("CompactDisc.class.php");
    include (
    "CDAudio.class.php");
    include (
    "CDAudioSingle.class.php");

    $cd = new CDAudioSingle();
    $cd->titre = "Rock'n PHP - Le Single";
    $cd->dateAchat = "25/12/2001";
    $cd->genreMusical = "Rock";

    $cd->afficherGenreMusical();
    ?>

    Ce qui affiche:
    Ceci est un single.
    Le genre musical est: Rock

    Quelques explications s'imposent:
    Dans la classe "CDAudioSingle" la fonction membre afficherGenreMusical() normalement héritée de "CDAudio" est redéfinie.
    Cette nouvelle fonction membre affiche "Ceci est un single" puis appelle la fonction membre afficherGenreMusical() de la classe de base (ici "CDAudio") gràce à l'emploi du mot clé parent et de l'opérateur :: (nommé ORP: Opérateur de Résolution de Portée).

    On a ainsi redéfini une fonction membre qui rempli des fonctions supplémentaires tout en appelant tout de même la fonction correspondante dans la classe de base.

    Remarque: L'opérateur :: peut également être utilisé avec le nom d'une classe afin d'appeller une fonction membre ou une variable membres dits "statiques" (ie qui ne dépendent d'aucun objet), à partir de l'extérieur de la classe et en l'absence d'un objet existant du type correspondant.
    La syntaxe est:
    nomDeLaClasse::nomDeLaFonction()
    Ce genre de chose est à éviter de préférence...

V) Polymorphisme

    La notion de polymorphisme est assez abstraite et assez peu utile en PHP. Cette notion découle directement de l'héritage. En observant les classes "CompactDisc" et "CDAudio", vous constatez que, à cause de l'héritage, la classe "CDAudio" possède toutes les caractéristiques de la classe "CompactDisc". Ainsi, deux objets respectivement de type "CompactDisc" et "CDAudio" peuvent tous deux être traités comme des objets de type "CompactDisc":

    
    $obj1 = new CompactDisc();
    
    $obj2 = new CDAudio();

    //...

    $obj1->afficherTitre();
    $obj2->afficherTitre();

    L'interêt n'est peut être pas évident sur cet example très simple, mais en reprenant le schéma vu précedemment, on constate que de nombreuses classes héritent de "CompactDisc". Ainsi, il est possible de créer des fonctions (non membres, indépendantes de toutes classes) qui prennent en paramètre des objets de type "CompactDisc" pour effectuer divers traitements (affichage, etc...)

    Le langage PHP n'étant pas typé (vous n'êtes pas obligé, à la création d'une variable, de spécifier le type de données quelle va recevoir), les avantages du polymorphisme sont forcément moins évidents que dans d'autres langages...

VI) Utilité et conclusion

    J'espère que ce long tutoriel vous aura laissé entrevoir toutes les possibilités offertes par l'héritage (sinon on récapitule):

    • L'héritage permet d'éviter de réécrire des fonctions déjà existantes qu'il suffit de réadapter (voir notre example de "CompactDisc" et de toutes ses classes dérivées)
    • L'héritage permet d'adapter et/ou spécialiser des classes déjà existantes (que vous avez trouvé sur Internet par exemple) afin qu'elles répondent à vos besoin, et cela, sans modifier les classes originales.
    • Sur des projets volumineux, une architecture de classes/héritage est plus simple à gérer
    • ...

    Si vous êtes arrivé jusqu'au bout de ces deux tutoriels sans trop d'encombres, nous pourrons passer à la notion de sérialisation (pour sauvegarder vos objets) et étudier plusieurs petits points importants (hygiène de code, programmation par composition, fonctions particulières, mutateurs, accesseurs,...)





Ajouter une réponse
Nom
Email
Titre

Mise en forme : gras = [b]...[/b], italic = [i]...[/i], souligné = [u]...[/u], citation = [quote]...[/quote], lien = [url]liens_externe[/url] ou [url nom=texte]liens_externe[/url], code source : [code]...[/code]

Mémoriser mon nom et mon email : Oui Non
www.phpdebutant.org © 2017 - L'équipe de phpDebutant - Hébergement : WDMédia-hébergement
DEBUTEZ !
 
  0.  Introduction
  1.  Afficher une phrase ou une image
  2.  Afficher la date et l'heure
  3.  PHP dans du code HTML
  4.  La concaténation
  5.  Récupérer les valeurs d'un formulaire
  6.  Les structures de contrôle
  7.  Ecrire et lire dans un fichier texte
  8.  Les fonctions utilisateurs
  9.  Les variables d'environnement
  10.  Quelques fonctions utiles
  11.  SQL/MySQL (Create, Alter & Drop)
  12.  SQL/MySQL (Insert et Select)
  13.  SQL/MySQL (Delete et Update)
  14.  SQL/MySQL (Where)
  15.  Fonctions PHP pour mySQL
  16.  Interroger une table MySQL
  17.  Alimenter une ou plusieurs tables mySQL
  18.  Les pseudos-frames
  19.  Les sessions php4
  20.  Affichage page par page
  21.  Images dynamiques
  22.  Ca marche pas ?
  23.  Variables globales à OFF
  24.  Les variables dynamiques