dimanche 21 août 2016

LA PROGRAMMATION ORIENTÉE OBJET


Il est possible de programmer en PHP de nombreuses façons différentes. C'est ce qui fait sa force : on peut en effet commencer à créer ses premières pages basiques en PHP avec très peu de connaissances au départ, mais il est aussi possible de programmer avec des outils avancés, plus complexes mais aussi plus solides et plus flexibles.
La programmation orientée objet est une technique de programmation célèbre qui existe depuis des années maintenant. PHP ne l'a pas inventée : d'autres langages comme le C++, Java et Python l'utilisaient bien avant lui.
La programmation orientée objet, que nous abrègerons POO, n'est pas le Saint Graal : elle ne va pas améliorer subitement la qualité de votre site comme par magie. En revanche, elle va vous aider à mieux organiser votre code, à le préparer à de futures évolutions et à rendre certaines portions réutilisables pour gagner en temps et en clarté. C'est pour cela que les développeurs professionnels l'utilisent dans la plupart de leurs projets.

Qu'est-ce qu'un objet ?

Je l'ai dit et je le répète : la programmation orientée objet ne va pas instantanément révolutionner votre site web, contrairement à ce que beaucoup semblent penser. En fait, il est même probable que cela vous semble un peu inutile au début et que vous vous disiez « O.K., mais je n'en vois pas l'intérêt, ça marchait aussi bien avant ». Certaines choses vous paraîtront aussi un peu abstraites, vous ne verrez peut-être pas bien comment mettre tout cela en pratique sur votre site. C'est parfaitement normal ; lorsqu'on apprend la programmation orientée objet, il y a un petit temps d'adaptation pendant lequel on ne voit pas le rapport entre la théorie et la pratique.
Prenez quand même le temps de tout lire et de faire l'effort de comprendre ce qui est expliqué. Petit à petit, en pratiquant, vous découvrirez que cela vous permet de mieux maîtriser votre code PHP au fur et à mesure qu'il grossit, et vous verrez par la suite tout l'intérêt de ce que vous aurez appris. ;-)

Ils sont beaux, ils sont frais mes objets

Nous allons commencer par définir ce qu'on appelle un objet en programmation. Alors, de quoi s'agit-il ?
Encore un concept mystique ? Un délire de programmeurs après une soirée trop arrosée ?
Non parce que franchement, un objet, c'est quoi ? Mon écran est un objet, ma voiture est un objet, mon téléphone portable… ce sont tous des objets !
Bien vu, c'est un premier point.
En effet, nous sommes entourés d'objets. En fait, tout ce que nous connaissons (ou presque) peut être considéré comme un objet. L'idée de la programmation orientée objet, c'est de manipuler dans son code source des éléments que l'on appelle des « objets ».
Mais concrètement, c'est quoi ? Une variable ? Une fonction ?
Ni l'un, ni l'autre. C'est un nouvel élément en programmation. Pour être plus précis, un objet c'est… un mélange de plusieurs variables et fonctions. Allez ne faites pas cette tête-là, vous allez découvrir tout cela par la suite.

Imaginez… un objet

Pour éviter que ce que je vous raconte ressemble à un traité d'art moderne conceptuel, on va imaginer ensemble ce qu'est un objet à l'aide de plusieurs schémas concrets. Les schémas 3D que vous allez voir par la suite ont été réalisés pour moi par Nab, que je remercie d'ailleurs vivement au passage.
Imaginez qu'un programmeur décide un jour de créer une section de son site web qui permette d'ajouter des membres, de les placer dans des groupes (administrateurs, modérateurs…), de les bannir, de les supprimer… Le code est complexe : il a besoin de créer plusieurs fonctions qui s'appellent entre elles, des variables pour mémoriser le nom du membre, sa date d'inscription, son groupe, etc.
Il met du temps à écrire ce code : c'est un peu compliqué, mais il y arrive. Au final, le code qu'il a écrit est composé de plusieurs fonctions et variables. Quand on regarde ça pour la première fois, ça ressemble à une expérience de savant fou à laquelle on ne comprend rien (figure suivante).
Notre code ressemble à une expérience de savant fou incompréhensible
Notre code ressemble à une expérience de savant fou incompréhensible
Ce programmeur est content de son code et veut le distribuer sur Internet pour que tout le monde puisse créer sa section membres sur son site sans avoir à tout recoder. Seulement voilà : à moins d'être un expert en chimie certifié, vous allez mettre pas mal de temps avant de comprendre comment tout ce bazar fonctionne.
Quelle fonction appeler en premier ? Quelles valeurs envoyer à quelle fonction pour créer le membre ?
C'est là que notre ami programmeur pense à nous. Il conçoit son code de manière orientée objet. Cela signifie qu'il place tout son bazar chimique à l'intérieur d'un simple cube. Ce cube est ce qu'on appelle un objet, comme sur la figure suivante.
Le code est placé dans une boîte qui en simplifie l'accès
Le code est placé dans une boîte qui en simplifie l'accès
Ici, une partie du cube a été volontairement mise en transparence pour vous montrer que nos fioles chimiques sont bien situées à l'intérieur du cube. Mais en réalité, le cube est complètement opaque, on ne voit rien de ce qu'il y a à l'intérieur (figure suivante).
Le programmeur ne voit pas l'intérieur (la partie compliquée)
Le programmeur ne voit pas l'intérieur (la partie compliquée)
Ce cube contient toutes les fonctions et les variables (nos fioles de chimie), mais il les masque à l'utilisateur.
Au lieu d'avoir des tonnes de tubes et de fioles chimiques dont il faut comprendre le fonctionnement, on nous propose juste quelques boutons sur la face avant du cube : un bouton « créer un membre », un bouton « bannir », etc. L'utilisateur n'a plus qu'à se servir des boutons du cube et n'a plus besoin de se soucier de tout ce qui se passe à l'intérieur. Pour l'utilisateur, c'est donc complètement simplifié.
En clair : programmer de manière orientée objet, c'est créer du code source (peut-être complexe), mais que l'on masque en le plaçant à l'intérieur d'un cube (un objet) à travers lequel on ne voit rien. Pour le programmeur qui va l'utiliser, travailler avec un objet est donc beaucoup plus simple qu'avant : il a juste à appuyer sur des boutons et n'a pas besoin d'être diplômé en chimie pour s'en servir.
Bien sûr, c'est une image, mais c'est ce qu'il faut comprendre et retenir pour le moment.

Vous avez déjà utilisé des objets !

Eh oui ! Vous vous souvenez de PDO ? Ne me dites pas que vous avez déjà oublié.
PDO est une extension de PHP et elle est codée en orienté objet. C'est ce qui explique que son mode d'emploi était légèrement différent des fonctions auxquelles nous étions habitués.
Je vous avais promis de vous expliquer plus en détail comment fonctionnait PDO, c'est maintenant l'occasion idéale ! Souvenez-vous de cette ligne qui nous permettait de nous connecter à la base de données :
<?php
$bdd = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '');
?>
En fait, $bdd n'est pas une variable mais un objet. On crée un objet à l'aide de la commande new suivie du nom de la classe.
Classe ? Objet ? Quelle est la différence ?
  • La classe est un plan, une description de l'objet. Imaginez qu'il s'agit par exemple des plans de construction d'une maison.
  • L'objet est une instance de la classe, c'est-à-dire une application concrète du plan. Pour reprendre l'exemple précédent, l'objet est la maison. On peut créer plusieurs maisons basées sur un plan de construction. On peut donc créer plusieurs objets à partir d'une classe.
La figure suivante schématise ce que je viens d'exposer.
Classes et objets
Classes et objets
Par conséquent, si l'on reprend le code précédent, vous aurez deviné que :
  • $bdd est l'objet ;
  • PDO est le nom de la classe sur laquelle est basé l'objet.
Un objet est, je vous le disais plus tôt, un mélange de fonctions et de variables. Lorsqu'on l'utilise, on fait appel à ses fonctions :
<?php
$bdd->query();
$bdd->prepare();
$bdd->execute();
?>
Cela signifie : exécuter la fonction query() de mon objet $bdd, puis la fonction prepare(), puis la fonction execute(), etc. La flèche -> est propre aux objets. Il faut donc comprendre que l'on exécute la fonction query() de l'objet $bdd qui représente la connexion à la base de données.
Autre exemple, imaginaire cette fois, pour être sûr que vous compreniez bien :
<?php
$maison1 = new Maison();
$maison2 = new Maison();
$maison1->nettoyer();
?>
Ici, nous avons plusieurs objets représentant des maisons ($maison1 et $maison2), mais nous n'appelons que la fonction nettoyer() de la maison 1 : c'est donc la seule qui sera propre.
Un des avantages de la programmation orientée objet, comme vous le voyez, c'est sa lisibilité. Ce code est facile à lire et à comprendre.
Nous allons maintenant apprendre dans la suite de ce chapitre à créer nos propres classes.

Créer une classe

Pour nos exemples, nous allons imaginer que nous créons une classe Membre qui représente un membre de notre site. Nous pourrons charger ce membre à partir des informations enregistrées en base de données, lui demander son pseudonyme, sa date d'inscription, mais aussi le bannir, le déconnecter du site, etc.
Le code d'une classe étant en général assez long, il est recommandé de créer un fichier PHP qui contiendra uniquement la définition de la classe et que l'on inclura à chaque fois qu'on en a besoin. Je vous recommande de créer un fichier nommé Membre.class.php.
Dans ce fichier Membre.class.php, commencez par inscrire le code suivant :
<?php
class Membre
{
}
?>
À l'intérieur des accolades, nous allons définir des variables et des fonctions membres de la classe. Un point de vocabulaire à ce sujet : certains développeurs utilisent d'autres mots pour désigner les variables et fonctions membres des classes. Les voici :
  • variables membres : aussi appelées attributs ou propriétés ;
  • fonctions membres : aussi appelées méthodes.
Essayons maintenant de définir ensemble quelques variables et fonctions dans la classe Membre.

Les variables membres

Les variables permettent de définir l'objet : c'est ce qui fait qu'il sera unique. Alors, qu'est-ce qui représente un membre ? Essayons de définir quelques-unes de ses propriétés. Si on en oublie ce n'est pas grave, on pourra toujours en rajouter par la suite. Un membre a :
  • un pseudonyme ;
  • une adresse e-mail ;
  • une signature ;
  • un statut (actif ou non, selon que son compte a été validé ou banni).
Nous allons stocker toutes ces informations dans des variables sous forme de texte. Complétez votre classe en rajoutant ces variables :
<?php
class Membre
{
private $pseudo;
private $email;
private $signature;
private $actif;
}
?>
Nous indiquons que notre classe Membre est composée de quatre variables : $pseudo$email,$signature et $actif. Pour l'instant, elles ne possèdent aucune valeur.
Pour le moment, ne vous préoccupez pas du mot-clé private devant ces noms de variables, je vous expliquerai un peu plus loin ce que cela signifie. ;-)

Les fonctions membres

Maintenant que nous avons défini les variables, nous pouvons créer quelques fonctions. Leur rôle sera :
  • soit de lire ou mettre à jour les variables. On parle de fonctions getters et setters ;
  • soit d'exécuter des actions plus complexes sur le membre (comme lui envoyer un e-mail).
Les getters et setters
Ce sont des fonctions qui commencent par get (si l'on veut récupérer le contenu d'une variable) ou parset (si l'on veut modifier le contenu d'une variable).
Prenons par exemple le pseudonyme : on va créer une fonction getPseudo qui renvoie le pseudo etsetPseudo qui modifie ce dernier.
<?php
class Membre
{
private $pseudo;
private $email;
private $signature;
private $actif;
public function getPseudo()
{
return $this->pseudo;
}
public function setPseudo($nouveauPseudo)
{
$this->pseudo = $nouveauPseudo;
}
}
Nous avons donc deux fonctions qui permettent de manipuler le pseudonyme du visiteur. Comme vous le voyez, elles sont vraiment très simples. Ainsi, getPseudo renvoie le pseudo :
<?php
public function getPseudo()
{
return $this->pseudo;
}
?>
La variable $pseudo est accessible dans les fonctions avec le préfixe $this->. Cela signifie : « Le pseudo de cet objet ». En effet, souvenez-vous, on peut créer plusieurs objets à partir d'une classe. Il peut y avoir plusieurs membres et chacun d'eux a un pseudo différent. Le préfixe $this-> permet d'indiquer que c'est bien le pseudonyme du membre sur lequel on travaille que l'on veut récupérer.
On fait de même avec une fonction setPseudo qui prend en paramètre le nouveau pseudo du membre et qui le place dans $this->pseudo.
Ces fonctions sont très simples et un peu inutiles, non ?
En fait, les getters et setters sont souvent des fonctions simples, mais l'intérêt est qu'on peut faire des calculs et des vérifications sur les données. Par exemple, on pourrait améliorer la fonction setPseudo comme ceci :
<?php
public function setPseudo($nouveauPseudo)
{
// Vérifier si le nouveau pseudo n'est ni vide ni trop long
if (!empty($nouveauPseudo) AND strlen($nouveauPseudo) < 15)
{
// Ok, on change son pseudo
$this->pseudo = $nouveauPseudo;
}
}
?>
Ainsi, on autorise le changement de pseudonyme uniquement s'il correspond à certains critères : pseudo non vide et longueur inférieure à quinze caractères. On pourrait profiter de cette fonction pour vérifier aussi la présence de caractères non autorisés.
L'intérêt de passer par une fonction pour modifier les variables est donc de pouvoir contrôler que l'on n'insère pas n'importe quoi. Pour l'adresse e-mail, on pourrait ainsi vérifier que celle-ci a la forme d'une véritable adresse e-mail (on pourrait utiliser une expression régulière !).
Les autres fonctions
Bien entendu, nous pouvons introduire n'importe quel autre type de fonction dans la classe Membre et pas seulement des fonctions qui se contentent de modifier les variables. À nous de décider quelles actions on veut pouvoir effectuer sur le membre : le bannir, lui envoyer un e-mail…
<?php
class Membre
{
public function envoyerEMail($titre, $message)
{
mail($this->email, $titre, $message);
}
public function bannir()
{
$this->actif = false;
$this->envoyerEMail('Vous avez été banni', 'Ne revenez plus !');
}
...
}
?>
La fonction envoyerEMail est toute simple : elle utilise la fonction mail() de PHP qui permet d'envoyer un e-mail, et se base sur l'adresse e-mail stockée dans l'objet ($this->email).
D'autre part, la fonction bannir() change le statut actif du membre pour indiquer qu'il n'est plus actif et lui envoie un e-mail pour l'avertir de son bannissement. On en profite pour réutiliser la fonctionenvoyerEMail() de notre classe. Vous remarquerez qu'on doit placer là aussi le préfixe $this-> devant le nom d'une fonction de la classe qu'on appelle.
C'est dans l'esprit de la programmation orientée objet : on réutilise du code déjà écrit pour éviter de réinventer la roue à chaque fois.

Créer un objet à partir de la classe

Actuellement, vous devriez avoir un fichier Membre.class.php qui contient la définition de la classe, c'est-à-dire les plans de construction de vos futurs objets :
<?php
class Membre
{
private $pseudo;
private $email;
private $signature;
private $actif;
public function envoyerEMail($titre, $message)
{
mail($this->email, $titre, $message);
}
public function bannir()
{
$this->actif = false;
$this->envoyerEMail('Vous avez été banni', 'Ne revenez plus !');
}
public function getPseudo()
{
return $this->pseudo;
}
public function setPseudo($nouveauPseudo)
{
if (!empty($nouveauPseudo) AND strlen($nouveauPseudo) < 15)
{
$this->pseudo = $nouveauPseudo;
}
}
}
?>
Maintenant que la classe est prête (même si on peut encore l'améliorer), on peut commencer à l'utiliser et donc à créer des objets. Créez un nouveau fichier (que vous appellerez comme vous voulez, par exempleindex.php), dans lequel vous allez créer et utiliser un objet de type Membre.
<?php
include_once('Membre.class.php');
$membre = new Membre();
$membre->setPseudo('M@teo21');
echo $membre->getPseudo() . ', je vais te bannir !';
$membre->bannir();
?>
On commence par inclure la définition de la classe Membre qui est située dans le fichierMembre.class.php. On utilise la fonction include_once() qui nous assure que le fichier n'a pas déjà été inclus ailleurs dans la page, ce qui aurait provoqué une erreur car il est interdit de définir deux fois une même classe.
On crée ensuite un nouvel objet de type Membre avec la ligne :
<?php
$membre = new Membre();
?>
Nous avons maintenant un objet $membre qui représente un membre vide. On lui définit ensuite un pseudo, on l'affiche, puis pour s'amuser on le bannit. ;-)
Vous avez donc là un exemple concret d'utilisation de la classe. Bien que celle-ci soit basique, vous pourriez déjà donner ce fichier Membre.class.php à des amis programmeurs, accompagné de préférence d'une petite documentation qui explique comment l'utiliser, et vos amis pourront comme vous créer et manipuler les données des membres.
Une classe, c'est donc un peu un package prêt à l'emploi. Elle contient son lot de variables et de fonctions. Pour l'utiliser, nous faisons tout simplement appel à ses fonctions sans nous soucier de ce qu'elles font à l'intérieur. Cela rejoint donc les schémas que je vous avais présentés au début de ce chapitre.
Les variables et le code des fonctions n'intéressent pas le programmeur qui utilise la classe. Il se contente simplement d'appuyer sur des boutons, c'est-à-dire d'appeler les fonctions dont il a besoin pour manipuler les données de son membre : « Donne-lui le pseudo M@teo21 », « Bannis-le », etc.

Constructeur, destructeur et autres fonctions spéciales

En plus des fonctions que nous avons créées dans notre classe Membre, il existe un certain nombre de fonctions « spéciales » qu'il vous faut connaître. On les appelle fonctions magiques ou encore méthodes magiques.
On les reconnaît facilement car leur nom commence par deux underscores (tiret bas, sous le chiffre 8 d'un clavier AZERTY français). Par exemple : __construct__destruct__get, etc.
Ici, nous allons nous intéresser plus particulièrement aux deux plus importantes d'entre elles : le constructeur et le destructeur.

Le constructeur : __construct

Lorsque vous créez un objet, comme nous l'avons fait précédemment, celui-ci est vide au départ. Ses variables membres ne contiennent rien. Ainsi notre membre n'avait pas de pseudo, pas d'adresse e-mail, rien.
<?php
$membre = new Membre(); // Le membre est vide
?>
Or, quand vous créez un objet comme cela avec new, il faut savoir que PHP recherche à l'intérieur de la classe une fonction nommée __construct. Jusqu'ici nous n'en avions pas créé : donc faute d'en trouver, PHP créait un objet vide.
Le rôle d'une fonction constructeur est justement de construire l'objet (non, sans blague !), c'est-à-dire de le préparer à une première utilisation. Dans notre cas, on aimerait par exemple charger en base de données les informations concernant le membre et insérer les bonnes valeurs dans les variables dès le départ.
<?php
class Membre
{
public function __construct($idMembre)
{
// Récupérer en base de données les infos du membre
// SELECT pseudo, email, signature, actif FROM membres WHERE id = ...
// Définir les variables avec les résultats de la base
$this->pseudo = $donnees['pseudo'];
$this->email = $donnees['email'];
// etc.
}
...
?>
Notre fonction constructeur prend un paramètre : l'id du membre. À partir de là, on peut charger en base de données les informations concernant le membre et les insérer dans l'objet : $this->pseudo$this->email
Comme notre constructeur prend un paramètre, il faudra désormais créer nos objets en envoyant un id :
<?php
$membre = new Membre(32); // Le membre n° 32 est chargé !
?>
Notre membre no 32 est maintenant prêt !
Il contient déjà le bon pseudonyme, la bonne adresse e-mail, etc. À vous de faire en sorte ensuite, lorsqu'on modifie par exemple son pseudo, que ce changement soit bien répercuté en base de données.

Le destructeur : __destruct

Moins couramment utilisé, le destructeur peut néanmoins se révéler utile. Cette fonction est appelée automatiquement par PHP lorsque l'objet est détruit.
Mais quand l'objet est-il détruit ?
Pour détruire un objet, ou toute autre variable, on peut le faire à la main avec la fonction unset() :
<?php
unset($membre);
?>
Si vous ne le faites pas, l'objet sera détruit à la fin de l'environnement dans lequel il a été créé. Si l'objet a été créé dans la page (comme c'était le cas dans index.php), il sera supprimé à la fin de l'exécution de la page.
C'est alors que le destructeur est appelé. Son rôle est de réaliser toutes les opérations nécessaires pour mettre fin à la vie de l'objet.
La classe PDO, par exemple, a besoin d'utiliser le destructeur pour fermer la connexion à la base de données. Elle envoie alors un signal à la base de données : « Fin de la connexion ».
Dans le cas de notre classe Membre, il n'y aurait rien de spécial à faire a priori. Néanmoins, pour tester le fonctionnement du destructeur, vous pouvez en créer un qui affiche un message signalant que l'objet va être détruit :
<?php
public function __destruct()
{
echo 'Cet objet va être détruit !';
}
?>
Vous verrez que ce message apparaît à la fin de la page dans notre cas. Si vous avez créé plusieurs objets, vous verrez autant de messages qu'il y a d'objets, car chacun d'eux va être détruit !

Les autres fonctions magiques

Il existe de nombreuses autres fonctions magiques dont l'utilité est cependant moins importante : __get(),__set()__call()__sleep()__wakeup()… Elles permettent de contrôler certaines autres étapes de la vie de votre objet.
Nous ne les détaillerons pas ici mais si vous voulez en savoir plus sur elles, vous pouvez lire la page de la documentation qui présente les fonctions magiques.

L'héritage

L'héritage est probablement le concept le plus important de la programmation orientée objet. C'est ce qui lui donne toute sa puissance. Cela permet de réutiliser des classes pour en construire de nouvelles. On se sert de certaines classes « de base » pour construire des classes plus complètes.

Comment reconnaître un héritage ?

C'est LA question à se poser. Certains ont tellement été traumatisés par l'héritage en cours de programmation qu'ils en voient partout, d'autres au contraire (surtout les débutants) se demandent à chaque fois s'il y a un héritage à faire ou non. Pourtant, ce n'est pas « mystique », il est très facile de savoir s'il y a une relation d'héritage entre deux classes.
Comment ? En suivant cette règle très simple :
Il y a héritage quand on peut dire : « A est un B ».
Pas de panique, ce ne sont pas des maths. ;-)
Prenez un exemple très simple. On peut dire « Un administrateur est un membre », ou encore « Un modérateur est un membre ». Donc on peut faire un héritage : « La classe Admin hérite de Membre », « La classeModerateur hérite de Membre ».
Pour vous imprégner, voici quelques autres bons exemples où un héritage peut être fait :
  • une voiture est un véhicule (Voiture hérite de Vehicule) ;
  • un bus est un véhicule (Bus hérite de Vehicule) ;
  • un moineau est un oiseau (Moineau hérite d'Oiseau) ;
  • un corbeau est un oiseau (Corbeau hérite d'Oiseau) ;
  • un chirurgien est un docteur (Chirurgien hérite de Docteur) ;
  • un diplodocus est un dinosaure (Diplodocus hérite de Dinosaure) ;
  • etc.
En revanche, vous ne pouvez pas dire « Un dinosaure est un diplodocus », ou encore « Un bus est un oiseau ». Donc on ne peut pas faire d'héritage dans ces cas-là, du moins ça n'aurait aucun sens. ;-)

Réaliser un héritage en PHP

Nous allons créer une nouvelle classe Admin qui sera basée sur la classe Membre. Elle aura toutes les variables et fonctions de la classe Membre, mais elle aura en plus de nouvelles variables et fonctions.
Créez un fichier Admin.class.php (souvenez-vous, on fait un fichier par classe !) et insérez-y le code suivant pour commencer :
<?php
include_once('Membre.class.php');
class Admin extends Membre
{
}
?>
Le nouveau mot-clé ici est extends, qui signifie « étend ». Traduction : la classe Admin étend [les possibilités de] la classe Membre. C'est cela l'héritage : nous avons maintenant une classe Admin qui possède toutes les variables et fonctions de Membre, et nous allons pouvoir en définir de nouvelles qui seront propres aux admins.
Rajoutons maintenant des fonctionnalités qui seront propres aux admins. Par exemple, ceux-ci, grâce à leurs privilèges, peuvent choisir la couleur dans laquelle sera écrit leur pseudonyme. Ils ont donc une variable$couleur et des fonctions qui permettent de la lire et de la modifier :
<?php
include_once('Membre.class.php');
class Admin extends Membre
{
private $couleur;
public function setCouleur()
{
// ...
}
public function getCouleur()
{
// ...
}
}
?>
Nous avons donc maintenant deux classes : Membre et Admin.
  • Avec Membre, on peut manipuler un pseudo, une adresse e-mail, une signature et un état actif ou non.
  • Avec Admin, on peut manipuler les mêmes choses : un pseudo, une adresse e-mail, une signature et un état actif ou non… mais aussi de nouvelles propriétés, comme la couleur du pseudo.
Dans notre fichier index.php on peut maintenant créer des membres mais aussi des admins :
<?php
$membre = new Membre(31); // Contient un pseudo, une adresse e-mail...
$maitreDesLieux = new Admin(2); // Contient les mêmes données qu'un membre + la couleur
$membre->setPseudo('Arckintox'); // OK
$maitreDesLieux->setPseudo('M@teo21'); // OK
$membre->setCouleur('Rouge'); // Impossible (un membre n'a pas de couleur)
$maitreDesLieux->setCouleur('Rouge'); // OK
?>
Avec peu d'efforts, nous avons créé une nouvelle classe qui réutilise une classe existante. On peut donc appeler la fonction setPseudo comme pour les membres, et on peut en plus effectuer de nouvelles opérations, comme définir une couleur de pseudo.

Les droits d'accès et l'encapsulation

Pour terminer notre découverte de la programmation orientée objet, il me reste à vous présenter un concept très important : l'encapsulation. En effet, il y a beaucoup de règles en POO et personne ne vous oblige à les suivre ; elles paraissent parfois lourdes et un peu contraignantes, ce qui fait que certains finissent par malprogrammer en POO.
Pourtant, s'il y a une règle à suivre en POO, c'est bien l'encapsulation. Cependant, avant de vous expliquer ce que cette règle raconte, je dois vous présenter le principe des droits d'accès.

Les droits d'accès

Vous vous souvenez de ces petits mots que nous avons utilisés devant nos noms de variables et fonctions dans ce chapitre ? Oui, je fais référence à public et private. Ce sont ce qu'on appelle des droits d'accès : cela permet d'indiquer si l'utilisateur de la classe a le droit d'accéder directement à un élément de la classe ou non.
Il y a trois droits d'accès à connaître :
  • public : tout le monde peut accéder à l'élément ;
  • private : personne (à part la classe elle-même) n'a le droit d'accéder à l'élément ;
  • protected : identique à private, sauf qu'un élément ayant ce droit d'accès dans une classe mère sera accessible aussi dans les classes filles.
Essayons de traduire tout ça en mots français, voulez-vous ?
Reprenons une version simple de notre classe Membre :
<?php
class Membre
{
private $pseudo;
private $email;
private $signature;
private $actif;
public function getPseudo()
{
}
public function setPseudo($nouveauPseudo)
{
}
}
?>
Ici, vous voyez que les fonctions sont publiques et les variables sont privées. Rien ne nous empêche cependant de faire l'inverse, même si ce n'est vraiment pas conseillé pour les variables, comme nous allons le voir.
Qu'est-ce que cela signifie, concrètement ? Que la personne qui utilise la classe à travers des objets (dansindex.php par exemple) peut uniquement accéder à ce qui est public et non à ce qui est privé :
<?php
$membre = new Membre(4);
$membre->setPseudo('M@teo21'); // OK car setPseudo est public
$membre->pseudo = 'M@teo21'; // Interdit car $pseudo est private
?>
C'est donc vous qui définissez avec ces publicprivate ou protected si l'utilisateur a le droit ou non d'appeler la fonction ou la variable.
Et protected justement, ça correspond à quoi ?
C'est identique à private mais il y a une différence lorsqu'on hérite de la classe. Par exemple, si on définit la variable $email comme protected dans la classe Membre, cela signifie que les classes qui en héritent (comme Admin) auront le droit d'y accéder. Sinon, en private, elles n'auraient pas pu les appeler directement.

L'encapsulation

Pourquoi est-ce qu'on s'embête avec ça ? Et si on mettait tout en public ? On se prendrait moins la tête, non ?
Si tout était public, même les variables membres, n'importe qui pourrait faire :
<?php
$membre = new Membre(4);
$membre->email = 'Portnawak';
?>
Or, « Portnawak » n'est pas une véritable adresse e-mail, je pense que vous serez d'accord avec moi.
Pour éviter qu'on puisse faire n'importe quoi avec ses objets, on a inventé une règle très simple qui s'appelle la règle d'encapsulation. On peut la résumer comme ceci :
Toutes les variables d'une classe doivent toujours être privées ou protégées.
Voilà pourquoi on prend l'habitude de créer des fonctions get et set : cela nous permet de vérifier qu'on ne fait pas n'importe quoi avec les variables, comme définir une adresse e-mail invalide.
Il arrive en revanche que l'on définisse des fonctions membres privées. Ce sont des fonctions internes à la classe que l'utilisateur n'a pas à appeler directement.
Le but de l'encapsulation est de masquer à la personne qui utilise la classe son fonctionnement interne. Quand vous créez un objet, vous ne devez pas avoir à vous soucier des variables qu'il contient, de la façon dont celles-ci sont agencées, etc. Vous êtes juste une personne qui appuie sur des boutons pour effectuer des actions sur l'objet (à ce propos, revoyez mes schémas du début du chapitre). Vous devez donc passer par des fonctions pour modifier vos objets.
Pour forcer l'utilisateur à « appuyer sur les boutons » plutôt que de « toucher aux fioles chimiques dangereuses qu'il ne comprend pas », on utilise les droits d'accès. Ainsi, les fonctions sont pour la plupart publiques (sauf celles qui servent au fonctionnement interne de la classe) et les variables sont toujours privées ou protégées pour que l'utilisateur ne puisse pas mettre n'importe quoi à l'intérieur.

En résumé

  • La programmation orientée objet est une autre façon de concevoir son code. Elle permet de concevoir les éléments de son site comme des objets à qui l'on donne des ordres et qui sont capables de modifier leur état.
  • La classe est le modèle à partir duquel on peut créer plusieurs objets.
  • Une classe est constituée de variables membres et de fonctions membres. Les fonctions modifient l'état des variables membres.
  • Le constructeur (nommé __construct()) est une fonction appelée par PHP lorsqu'on crée un objet basé sur la classe. De même pour __destruct(), appelée lors de la suppression de l'objet.
  • Une classe peut hériter d'une autre classe pour récupérer toutes ses propriétés et rajouter de nouvelles fonctionnalités spéciales.
  • On oblige le programmeur qui utilise la classe à passer par des fonctions pour modifier l'objet. C'est leprincipe d'encapsulation.
source: OpenClassrooms

Aucun commentaire:

Enregistrer un commentaire