Partie 3: Sérialisation et points importants
Un dernier thème important reste à aborder, c'est la sérialisation des objets afin de pouvoir les manipuler simplement. Nous irons alors plus loin avec un petit morceau sur des fonctions parfois utiles (mais facultatives) pour la sérialisation.
Un dernier point très important restera les notions de "composition ou héritage ?" qui doivent vous guider dans l'étape de conception d'un projet.
Prérequis: Les deux premières parties du tutoriel, passage de variables entre deux pages
|
I) La sérialisation: fonctionnement et intêrets
La sérialisation est un moyen simple de sauvegarder vos objets (dans une variable, un fichier, une base sql,...) afin de les réutiliser ultérieurement.
Vous pouvez notamment passer un objet d'une page à une autre.
Pour cela on dispose des deux fonctions suivantes:
$chaine = serialize ($objet);
$objet = unserialize ($chaine);
La fonction serialize permet donc de convertir un objet passé en paramètre en une variable chaine contenant la valeur de chacune des variables membres de l'objet à sérialiser.
La fonction unserialize effectue l'opération inverse.
La fonction serialize ne sauvegarde en aucun cas les fonctions membres d'un objet. Ainsi, lors de l'appel à la fonction unserialize, la classe correspondante
doit être déclarée. On voit ici l'interêt de mettre les classes dans des fichiers séparés. (si vous ne voyez pas l'interêt, regardez l'exemple suivant)
|
Créons deux pages: index.php et genre.php basées sur les classes CompactDisc et CDAudio définies dans les fichiers respectifs CompactDisc.class.php et CDAudio.class.php (voir tutoriel précédent)
Sur la page index, une liste de plusieurs CDAudio est présentée et chacun d'entre eux possède un lien vers la page genre.php qui se chargera d'afficher le genre musical du CDAudio choisis.
Pour réaliser cela, le lien contenu dans index.php pointeras vers genre.php en passant en paramètre un objet sérialisé. Tout sera plus clair avec le code suivant:
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";
$cdSerial = serialize($cd);
$param = urlencode($cdSerial);
echo "<A HREF='genre.php?var=$param'>Afficher le genre</A>";
?>
|
Fichier "genre.php"
<?
include ("CompactDisc.class.php");
include ("CDAudio.class.php");
$param = stripslashes(urldecode($var));
$cdDeSerial = unserialize ($param);
echo $cdDeSerial->afficherGenreMusical();
?>
|
Ce qui donne:
Après le clic sur le lien
Le genre musical est: Rock
|
Pour information, après sérialisation de l'objet $cd dans index.php, la variable $cdSerial reçoit la chaine de caractères:
O:7:"cdaudio":3:{s:5:"titre";s:10:"Rock'n PHP";s:9:"dateAchat";s:10:"25/12/2001";s:12:"genreMusical";s:4:"Rock";}
Vous y reconnaitrez le nom de la classe et les variables membres de l'objet, composées de leur nom et de leur valeur.
Quelques éclaircissements sont nécessaires sur les appels aux fonctions urlencode(), urldecode() et stripslashes(). Dans notre exemple, nous avons passé notre
objet, après serialisation, via une URL (ie un appel du type http://domaine.com/index.php?nomDeVariable=valeur).
Vous devez savoir que tous les caractères ne sont pas permis. Ainsi, il est nécessaire d'utiliser la fonction urlencode pour les remplacer, puis urldecode pour
revenir à l'état précédent. La fonction stripslashes permet quant à elle de retirer les "\" ajoutés par urlencode() et non retirés par urldecode().
Le reste est assez explicite, n'hésitez pas à essayer vous même pour bien comprendre le fonctionnement du système.
Au travers de cet exemple, nous avons vu le fonctionnement principal de la serialisation. Notez qu'un objet serialisé peut être enregistré dans un fichier ou dans un champ d'une base MySQL (dans ce cas, préferez des types "text" plutot que varchar car vous ne connaissez pas, à priori, la taille de la variable contenant l'objet sérialisé à enregistrer).
II) Fonctions __sleep et __wakeup
Ces deux fonctions, lorsqu'elles sont déclarées comme fonctions membres d'une classe peuvent s'avérer très pratiques. En effet, la fonction serialize() cherche si la fonction __sleep est définie et l'appelle automatiquement le cas échéant, avant d'effectuer la sérialisation.
A l'inverse, la fonction unserialize() cherche si la fonction __wakeup() est définie et l'appelle automatiquement le cas échéant, après avoir effectué la déserialisation.
L'intérêt de la fonction __sleep() est de permettre un "nettoyage" de l'objet si nécessaire et/ou de fermer la connection à une base de données. La fonction __wakeup est principalement utilisée pour rétablir une connection à une base de données.
La fonction __sleep() doit impérativement retourner sous forme d'un tableau la liste des variables membres à serialiser. Ceci permet de décider quelles variables doivent être sauvegardées et lesquelles doivent être ignorées (des variables temporaires ou dépendant du contexte, par exemple).
|
Modifions la classe CDAudio pour appliquer tout ceci:
Fichier "CDAudio.class.php"
<?php
class CDAudio extends CompactDisc {
var $genreMusical ;
function afficherGenreMusical() {
echo "<BR>Le genre musical est: ".$this->genreMusical;
}
function __sleep() {
// Fermeture d'une connection MySQL:
mysql_close();
$ASauver[0] = "titre";
$ASauver[1] = "dateAchat";
$ASauver[2] = "genreMusical";
return $ASauver;
}
function __wakeup() {
// Réouverture d'une connection MySQL:
mysql_connect("serveur", "utilisateur", "motDePasse");
mysql_select_db("base");
}
}
?> |
Dans ce cas, les 3 variables membres $titre, $dateAchat et $genreMusical seront incluses dans la sérialisation. Ainsi, l'appel à serialize() appellera __sleep() qui se chargera de fermer la connection MySQL; l'appel à unserialize() appellera __wakeup() qui se chargera d'ouvrir une connection MySQL.
III) Opérateur de Résolution de Portée (ORP) et mot clé "parent"
Si vous avez des difficultés avec tout ce qu'on a vu jusqu'à présent, sautez ce paragraphe, il ne vous apportera rien...
L'ORP est noté :: et permet d'accéder à une fonction membre dans les cas suivants:
- En l'absence d'instance de la classe, on peut ainsi accéder à des fonctions membres de la classe (qui ne devraient donc pas dépendre de variables membres).
- Pour appeller une fonction membre d'une classe de base à partir de la redéfinition de celle-ci dans une classe héritée (exemple ci-dessous)
<?php
class Vehicule {
function acheter() {
echo "Fonction membre acheter de la classe Vehicule";
}
}
class Voiture extends Vehicule {
function acheter() {
echo "Fonction membre acheter de la classe Voiture";
// On appelle également celle de la classe de base:
Vehicule::acheter();
}
}
?>
|
De la même façon, le mot clé parent associé à l'ORP permet de désigner génériquement la classe de base à partir d'une classe héritée.
Ainsi, on aurait pu, dans l'exemple précédent, remplacer la ligne
Vehicule::acheter();
par:
parent::acheter();
Le mot clé
parent, tout comme le mot clé
this ne peut bien sur être utilisé qu'à l'intérieur d'une classe. De plus
parent ne peut être utilisé que si la classe courante dérive d'une autre classe.
IV) Programmation par composition
Pour compléter ce tour d'horizon, il me semblait nécessaire d'aborder un sujet très important en programmation objet. Vous devez être parfaitement conscient de ces idées lorsque vous concevrez une architecture de classes.
Je ne reviendrai pas sur l'héritage étudié précedemment. La notion de composition (il existe de nombreux termes synonymes) est toute simple. Elle correspond à l'utilisation, en tant que variable membre d'une classe, d'un objet issu d'une autre classe. Il existe donc une relation entre ces deux classes puisque la première ne peut "vivre" sans la deuxième (la réciproque étant fausse).
Exemple simple:
<?php
class Homme {
var $nom, $prenom;
function Homme ($strNom, $strPrenom) {
// Constructeur de la classe
$this->nom=$strNom;
$this->prenom=$strPrenom;
}
function afficherIdentite () {
echo $this->nom."<BR>".$this->prenom."<BR>";
}
}
class Livre {
var $titre, $auteur;
function Livre ($strTitre) {
// Constructeur de la classe
$this->titre = $strTitre;
$this->auteur = new Homme ("Lerdorf", "Rasmus");
}
function afficherInfos() {
echo $this->titre."<BR>";
$this->auteur->afficherIdentite();
}
}
$php = new Livre("PHP Facile");
$php->afficherInfos();
?>
|
Ce qui donne bien sur le résultat escompté...
Gardez toujours en tête les notions d'héritage et de composition lors de la conception de vos classes. Néanmoins, ne vous forcez pas à utiliser ces deux systèmes pour chaque classe !
|
V) Conclusion: le futur
Le futur de la programmation objet en PHP est très chargé. Le moteur objets de PHP 5 sera bien plus performant et plus puissant et ce tout en restant très simple d'emploi.
A cela, il faudra ajouter PEAR qui deviendra un outil très simple d'emploi et permettra de réaliser encore plus facilement de nombreuses taches. En effet, PEAR sera tout simplement une architecture de classes destinées à être utilisées par les programmeurs PHP que vous êtes. D'après les tendances, on peut prédire que PEAR deviendra un composant incontournable et essentiel de PHP dans les mois qui viennent. Des connaissances en programmation objet (notamment pour se servir des classes de PEAR ou les adapter à vos propres besoins par l'héritage) seront absolument nécessaires...
J'espère donc que cette série de 3 tutoriels vous auront permis d'y arriver !