Dans ma longue liste des choses que j'ai promises, il y a de la documentation pour utiliser des objets en PHP. Oui, ça veut dire « faire de la Programmation Orientée Objet avec PHP ».
Étant donné qu'il y a des experts qui font des bouquins super épais sur le sujet, ne vous attendez pas à un truc super complet. Je vais simplement essayer de rendre la chose pas trop complexe. N'hésitez pas à vous plaindre dans les commentaires.
La programmation orientée objet (POO pour les intimes), c'est simplement une syntaxe spéciale, dont le but principal de faciliter la réutilisation du code.
Imaginons que vous vouliez gérer une collection de CD. Voici le code pour afficher un CD :
<?php
$cd1 = array('Ich bin Olivier', 'La Ciotat Camping', 2008, 3);
echo 'Album : '.$cd1[0].'<br/>';
echo 'Artiste : '.$cd1[1].'<br/>';
echo 'Année : '.$cd1[2].'<br/>';
echo 'Note : '.$cd1[3].'/5<br/>';
?>
Ce qui donne :
Album : Ich bin Olivier
Artiste : La Ciotat Camping
Année : 2008
Note : 3/5
À part le fait que j'utilise la seule phrase que je connais en allemand pour rivaliser avec un groupe à la capillarité explosive, on peut déjà voir quelques améliorations pour ce code (même s'il fonctionne bien).
Si j'ai besoin de refaire la même chose pour un autre CD, je vais être obligé de recopier les 5 lignes, mais en changeant seulement la première. Le code est encore simple, mais si j'avais ajouté, par exemple, une vérification pour que la note ne dépasse pas 5, le code pourrait facilement être plus gros.
Je pourrais faire une fonction affiche_album($cd) qui afficherait le CD, mais si je change le format du CD, par exemple en ajoutant la durée avant la note, la fonction n'affiche plus les bonnes infos.
Il faut garder à l'esprit que réutiliser du code fait gagner vraiment beaucoup de temps, et que si j'ai copié/collé ce code dans 5 ou 6 pages, à différents endroits, un changement de format ou d'affichage (ex : « on pourrait pas mettre l'artiste avant le titre de l'album ? ») représente beaucoup de boulot.
class Cd {
public $album, $artiste, $annee, $note;
public function __construct($album, $artiste, $annee, $note) {
$this->album = $album;
$this->artiste = $artiste;
$this->annee = $annee;
$this->note = $note;
}
public function affiche_cd() {
echo 'Album : '.$this->album.'<br/>';
echo 'Artiste : '.$this->artiste.'<br/>';
echo 'Année : '.$this->annee.'<br/>';
echo 'Note : '.$this->note.'/5<br/>';
}
}
$cd1 = new Cd('Ich bin Olivier', 'La Ciotat Camping', 2008, 3);
$cd1->affiche_cd();
Dans la première partie, j'ai déclaré une classe d'objets Cd avec le mot-clé "class" (par convention, le nom des classes utilisent des majuscules comme séparateur, par exemple MonObjet). Dans cette classe, j'ai déclaré des variables, qu'on appelle aussi des membres, ainsi que des fonctions, qu'on appelle aussi méthodes.
Les variables correspondent aux quatre informations sur le CD qu'on déclare
"public".
La fonction __construct est le constructeur d'un objet,
c'est-à-dire la fonction qui sera appelé lors de la création de l'objet
(j'utilise volontairement la syntaxe PHP5, il y a 2 "_" devant le mot
construct).
La fonction affiche_cd
fait simplement l'affichage des informations du CD.
Les 2 dernières lignes utilisent simplement l'objet. La création se fait avec le mot "new", en utilisant le nom de la classe comme fonction. Cd est une classe, $cd1 est un objet. Une fois l'objet créé, on appelle ses fonctions avec l'opérateur "->", qui ressemble à une flèche (pour information, dans d'autres langages, on utilise parfois un point plutôt qu'une flèche).
Par rapport au code précédent, c'est plus long dans l'exemple, mais la déclaration de l'objet sera faite une seule fois pour tout un site, en la mettant dans un fichier à inclure. Ensuite, pour chaque affichage, on a juste à écrire 2 lignes. Et si on doit changer l'affichage, on le fait dans un seul fichier, une seule fois.
Le mot "public" signifie qu'on autorise l'utilisateur à lire et modifier
$cd->artiste (par exemple)
et les fonctions peuvent être appelées directement.
À la place de "public", on pourrait déclarer les variables "private"
pour que seule les fonctions puissent les modifier.
L'utilisation de $this-> permet de faire référence
aux variables et fonctions de l'objet courant.
C'est ce qui permet, dans le constructeur, de remplir les variables
de l'objet avec les paramètres du constructeur.
On vient de voir un objet avec un constructeur, c'est-à-dire la fonction qui est appelé lors de la création de l'objet.
Par exemple, on peut avoir une base de donnée, et vouloir créer l'objet à partir simplement d'un numéro de CD.
class Cd {
public $album, $artiste, $annee, $note, $num;
public function __construct($num) {
$this->num = $num;
... Connexion à la base de données ...
... Récupération des informations ...
... Remplissage de $album, $artiste, $annee, $note ...
... Déconnexion de la base de données ...
$this->album = $album;
$this->artiste = $artiste;
$this->annee = $annee;
$this->note = $note;
}
public function affiche_cd() {
echo 'Album : '.$this->album.'<br/>';
echo 'Artiste : '.$this->artiste.'<br/>';
echo 'Année : '.$this->annee.'<br/>';
echo 'Note : '.$this->note.'/5<br/>';
}
}
$cd1 = new Cd(15);
$cd2->affiche_cd();
Je n'ai pas mis le code de connexion à la base de données parce qu'il est un peu plus compliqué, mais j'espère que vous comprendrez le principe.
Grâce à l'utilisation des objets, on a simplement changé le constructeur
et on bénéficie de la fonction affiche_cd() sans rien changer
d'autre.
Le problème qu'on a maintenant, c'est que si on modifie le CD, il faut
ensuite le mettre à jour dans la base de données.
C'est pour cela qu'on va utiliser un destructeur.
un destructeur est simplement une fonction qui est appelé lorsque l'objet
est détruit, notamment à la fin de la page, ou lorsqu'on l'écrase avec
une nouvelle valeur (ex : $cd1 = 0).
public function __destruct($num) {
... Connexion à la base de données ...
... Mise à jour des informations ...
... Déconnexion de la base de données ...
}
Et voilà !
On a maintenant un objet qui permet de créer et de manipuler facilement une
petite collection de CD, en leur attribuant des notes.
Si on mets le code de l'objet dans un fichier Cd.php, on se retrouve avec
un code très court et très facile à comprendre et à utiliser.
Voici le code pour prendre un CD de la base de données, mettre sa note à 5,
l'afficher et le mettre à jour dans la base, en 3 lignes :
$cd2 = new Cd(15); // le constructeur va chercher le CD 15 dans la base $cd2->note = 5; // on l'aime bien celui-là ! $cd2->affiche_cd(); // on affiche les informations // et c'est tout : le destructeur fera son boulot tout seul
Pour être vraiment optimal, on aurait même pu économiser une connexion à la base de données en ouvrant la connexion dans le constructeur et en la fermant dans le destructeur.
L'héritage est souvent mis en avant comme une des choses les plus pratiques en POO, puisqu'il permet de réutiliser un objet complet.
Imaginons que je souhaite faire un quizz sur le site, qui consiste à
deviner les artistes et l'année en affichant le nom de l'album.
Ce qu'il me faut, c'est une classe Cd,
mais avec une modification de l'affichage :
class CdQuizz extends Cd {
public function affiche_cd() {
echo 'Album : '.$this->album.'<br/>';
echo 'Devinez le reste !<br/>';
}
}
Et voilà, c'est tout.
On a maintenant une classe
CdQuizz qui fonctionne exactement
comme Cd
(constructeur, gestion de la base de données, etc.),
mais qui n'affiche que le titre de l'album.
La première erreur est de
faire n'importe quoi avec l'héritage,
et de remonter les fonctions depuis les classes filles.
Par exemple, si on crée une classe Véhicule,
puis on hérite en Voiture et en
Camion, en rajoutant à chaque fois la fonction
tour_par_minute().
Comme la fonction est commune, on l'ajoute à Véhicule.
Et Paf ! Vous revenez 2 semaines après, vous créer
Fusée à partir de Véhicule,
et vous vous demandez pourquoi votre fusée a une fonction
tour_par_minute() !
Dans ce cas, la solution est de créer une classe intermédiaire
VéhiculeTerrestre qui a la fonction tour_par_minute() et
dont hériteront Voiture et Camion.
La deuxième erreur est de ne pas concevoir ses objets pour qu'ils
fonctionnent
correctement dans toutes les situations.
Le meilleur exemple, c'est le code que je vous ai donné !
En effet, comme $cd->num est public, rien n'empêche de faire
$cd->num = 5, et au moment de la destruction,
l'objet $cd ira écraser le CD 5 dans la base de données.
La mauvaise chose, c'est de dire
« C'est pas grave, je ferai attention quand je l'utiliserai », parce que vous
pouvez être sûr qu'un jour vous ferez la boulette.
La troisième et dernière erreur fréquente, qui est spécialement dédicacée
à mon pote Rémi, c'est de ne pas
aller voir la doc de PHP
quand on a un problème.
La documentation
sur les objets en PHP5 en français est très claire, si on se donne la
peine de la lire correctement.
Tout est documenté, et en particulier les problèmes que vous pourriez avoir
lorsque vous redéfinissez un constructeur dans une classe fille, ainsi que
pleins d'autres choses sympas, comme la visibilité (public, protected, private)
et les méthodes magiques.
) :D'un naturel joyeux, positif et curieux, je m'intéresse à beaucoup de choses parmi lesquels la salsa, l'espéranto, la plongée mais surtout l'informatique, le web et Linux (Mandriva).
Même si j'aime programmer, je m'intéresse également aux aspects d'ergonomie, de design et de marketing.
Je suis actuellement développeur firmware chez Neotion. Pour savoir comment j'en suis arrivé là, il y a mon CV.
M'écrire : olivier+blog@faurax.fr
Retrouvez-moi sur Facebook, Friendfeed, Identi.ca et Twitter.
