reseau social

Les constructeurs et destructeurs de PHP

Un article de ToutProgrammer.com.

Comme nous allons le voir, le constructeur d'objet a existé dès PHP 4. Avec PHP 5, de nouveaux mots clés permettant l'initialisation et la destruction des objets sont ajoutés.

Sommaire

[modifier] Le constructeur orphelin de PHP 4

Tous les grands langages objets offrent des méthodes spéciales que l'on appelle "constructeurs". Ces constructeurs sont destinés à initialiser spécifiquement l'objet lors de son instanciation. Dans la plupart des cas, des paramètres sont donnés au constructeur et c'est eux qui serviront à personnaliser l'objet. En plus du constructeur, il existe souvent un destructeur. Ce destructeur peut servir à libérer des zones mémoires (c'est le cas par exemple en C++) ou pourquoi pas à fermer des connexions à la base de données.

PHP 4 ne possède pas de mécanisme utilisé lors de la destruction d'un objet alors qu'il offre ce qu'il faut pour la construction. Voici un exemple de classe utilisant un constructeur:

  1. <?php
  2. // La ligne ci-dessous permet d'afficher tout texte comme texte simple et non comme
  3. // du HTML. C'est utile si nous utiliserons la fonction print_r/print('\n')
  4. // (voir la documentation PHP pour plus d'info)
  5. header("Content-type: text/plain");
  6.  
  7. class Utilisateur {
  8. function Utilisateur($nom, $prenom) {
  9. print("Utilisateur(\$nom, \$prenom) appelé\n");
  10. }
  11. }
  12.  
  13. $utilisateur = new Utilisateur("MARTIN", "Paul");
  14. ?>

Comme nous le voyons, un constructeur porte le même nom que celui de sa classe. Il peut prendre des paramètres voire aucun. Il n'est pas possible de définir plusieurs constructeurs (contrairement à C++ ou Java) car la surcharge n'est pas permise avec PHP (langage à typage faible).

Comme il n'existe pas de destructeur avec PHP 4, il faut créer une méthode "spéciale" qui va permettre de libérer les ressources réservées par l'objet. Il faudra alors appeler explicitement ce pseudo destructeur. Voici ce qui pourrait exister:

  1. <?php
  2. // La ligne ci-dessous permet d'afficher tout texte comme texte simple et non comme
  3. // du HTML. C'est utile si nous utiliserons la fonction print_r/print('\n')
  4. // (voir la documentation PHP pour plus d'info)
  5. header("Content-type: text/plain");
  6.  
  7. class BaseDeDonnees {
  8. // Constructeur
  9. function BaseDeDonnees($hote, $base, $identifiant, $motDePasse) {
  10. print("Ouverture de la connexion à la base de données.\n");
  11. }
  12.  
  13. // Pseudo destructeur
  14. function free() {
  15. print("Fermeture de la connexion à la base de données.\n");
  16. }
  17. }
  18.  
  19. $db = new BaseDeDonnees("localhost", "maBaseDeDonnees", "identifiant", "motdepasse");
  20. $db->free();
  21. ?>

Ne pas appeler la méthode free ne semble pas trop gênant en soit car PHP ferme automatiquement la connexion de base de données, mais celle-ci restera tout de même ouverte jusqu à la fin du script. Puisque PHP peut aussi servir au développement de scripts shell classiques avec CLI (Command Line Interface) ou GTK, il ne faut plus partir du principe que PHP fait tout comme il faut, quand il le faut.

Si vous avez un script très long et que vous gardez un connexion ouverte vers la base de données alors que vous n'en avez plus besoin et si le serveur de base de données limite le nombre de connexions (ce qui sera toujours le cas), aucun autre programme ne pourra établir son lien vers la source de données commune. Donc, dès qu'un objet n'est plus utilisé, il doit libérer ses ressources.

Mais devoir appeler explicitement une méthode, dont le nom n'est même pas normalisé, augmente le risque d'oubli. Si l'objet utilisait lui même d'autres objets, qu'elles seront les méthodes à appeler pour libérer les ressources de chacun de ces autres objets ? Tout cela n'est pas très simple.

[modifier] PHP 5, un constructeur et un destructeur uniformisés

Avec PHP 5, les choses deviennent plus simples et plus logiques: toute méthode réservée par PHP 5 est préfixée par __ (double soulignement ou underscore). C'est le cas notamment du constructeur déclaré par la méthode __construct et du destructeur déclaré par __destruct. Il faut noter malheureusement, qu'il n'est toujours pas possible de déclarer plusieurs constructeurs avec des paramètres différents alors qu'il est maintenant possible de typer les paramètres de méthode.

Voici un exemple d'utilisation de constructeur et de destructeur:

  1. <?php
  2. // La ligne ci-dessous permet d'afficher tout texte comme texte simple et non comme
  3. // du HTML. C'est utile si nous utiliserons la fonction print_r/print('\n')
  4. // (voir la documentation PHP pour plus d'info)
  5. header("Content-type: text/plain");
  6.  
  7. class Utilisateur {
  8.  
  9. private $nom = null;
  10. private $prenom = null;
  11. private $dateNaissance = null;
  12.  
  13. function Utilisateur($nom, $prenom, $dateNaissance=null) {
  14. print("Utilisateur(\$nom, \$prenom, \$dateNaissance=null) appelé\n");
  15. }
  16.  
  17. function __construct($nom, $prenom, $dateNaissance=null) {
  18. print("__construct(\$nom, \$prenom, \$dateNaissance=null) appelé\n");
  19. $this->nom = $nom;
  20. $this->prenom = $prenom;
  21. $this->dateNaissance = $dateNaissance;
  22. }
  23.  
  24. function __destruct() {
  25. print("__destruct() appelé\n");
  26. unset($this->nom);
  27. unset($this->prenom);
  28. unset($this->dateNaissance);
  29. }
  30. }
  31.  
  32. $utilisateur = new Utilisateur("MARTIN", "Pierre");
  33. unset($utilisateur);
  34. ?>

Vous remarquerez à l'exécution que l'ancien constructeur PHP 4 n'est plus utilisé. C'est totalement normal dès que vous utilisez un constructeur de type PHP 5. Ceci permet une compatibilité ascendante de PHP et ainsi de pouvoir continuer d'utiliser des classes développées pour PHP 4 avec la dernière version du langage.

L'appel du destructeur est fait implicitement par le moteur de PHP à la fin du script. Mais si vous souhaitez faire de la programmation propre, vous devez l'appeler explicitement avec le mot clé unsetqui existe déjà avec PHP 4. C'est ce que nous faisons avec le unset($utilisateur) à la fin du code. Nous le faisons aussi dans le destructeur de la classe Utilisateur.

Si nous avions utilisé des objets pour stocker les attributs de cette classe (des objets Stringpar exemple), leurs destructeurs respectifs auraient, eux aussi, été appelés produisant un effet "domino" sur l'ensemble des objets utilisés.

Pour les connaisseurs, l'équivalent du mot clé unseten langage C++ est delete (un temps envisagé semble-t-il avec PHP 5).

[modifier] Conclusion

Comme nous venons de le voir dans cet article, la plus grande innovation concerne incontestablement le destructeur qui permettra enfin de réaliser des développements plus propres en libérant les ressources du systèmes. Ce destructeur devient inévitable car il sera de plus en plus normal de développer de véritables applications standalonesavec PHP-GTK (par exemple). Il ne faudra plus attendre que PHP fasse le ménage en fin de script sachant que l'application pourra fonctionner pendant plusieurs jours et épuiser petit à petit la mémoire de la machine.

Le destructeur n'est tout de même pas la solution miracle si le développeur ne libère pas de lui même les ressources réservées dans le destructeur, il n'est pas compliqué de voir que cela reviendra à faire ni plus ni moins ce que fait déjà PHP 4 c'est à dire, pas grand chose.

[modifier] Historique de l'article

Cet article, réalisé par Stéphane VANPOPERYNGHE, a été publié pour la première fois le 2 février 2004 sur le site ToutProgrammer.com (1ème version).