reseau social

Une gestion plus logique des objets en PHP

Un article de ToutProgrammer.com.

Avec PHP 5, le langage PHP entre véritablement dans le monde objet grace à une gestion bien plus évoluée des références que celle que l'on peut avoir avec PHP 4. En effet, PHP 4 offre une gestion "étrange" des références qui à tendance à alourdir l'utilisation des objets ce qui est bien dommage pour un langage qui possède tant d'atouts.

[modifier] L'objet dans PHP 4

Le moteur de PHP 4, le Zend Engine 1.0, permettait pour la première fois dans le monde PHP d'utiliser la programmation orienté objet (POO). Mais malheureusement l'objet dans PHP n'a pas réussi à s'implanter sur les serveurs ce qui n'a fait que retarder l'entrée de PHP comme langage professionnel au même titre que Java (avec ses JSP) ou les ASP.

Une des caractéristiques de PHP 4 est la possibilité de travailler avec des références sur les objets. Mais leur utilisation est plus qu'aléatoire puisque le langage n'utilise pas de lui même ces références et c'est donc au développeur de faire une très grosse partie du travail avec des risques non négligeables de bogues particulièrement difficiles à localiser (surtout lorsque le PHP objet est inhabituel pour le développeur).

Cette version de PHP manipule uniquement les valeurs des variables. En clair, cela signifie que le programme travaille toujours avec des copies d'objets et il n'est pas très difficile de démontrer les problèmes engendrés par ce mode de fonctionnement.

  1. <?php
  2. class maClasse
  3. {
  4. var $attribut;
  5.  
  6. function setAttribut($valeur)
  7. {
  8. $this->attribut = $valeur;
  9. }
  10.  
  11. function getAttribut()
  12. {
  13. return($this->attribut);
  14. }
  15. }
  16.  
  17. // Instanciation de l'objet
  18. $objetA = new maClasse();
  19. $objetB = $objetA;
  20.  
  21. // Appelle du setter
  22. $objetA->setAttribut("AZERTY");
  23. echo "Valeur de l'attribut de objetA: ".$objetA->getAttribut()."<br>\n";
  24.  
  25. // Affichage du contenu avec le getter de $objetB
  26. echo "Valeur de l'attribut de objetB: ".$objetB->getAttribut()."<br>\n";
  27. ?>

Nous voyons que le résultat n'est pas celui auquel on aurait pu s'attendre, mais cela démontre bien que l'objet objetB est une copie de l'objet objetA avant l'appel de $objetA->setAttribut().

Alors on peut se demander s'il est possible de ne pas travailler sur une copie de l'objet en PHP 4. La réponse est OUI bien entendu mais c'est un peu plus lourd. Voici ce qu'il faut faire lors de l'instanciation et la copie d'objets:

  1. <?php
  2. // Instanciation de l'objet
  3. $objetA =& new maClasse();
  4. $objetB =& $objetA;
  5. ?>

L'esperluette (signe &) permet d'indiquer à PHP que l'on travaille avec des références sur les objets et plus avec des copies. Dès lors, si vous relancer le programme, vous devriez voir que les attributs des objets objetA et objetB sont bien les mêmes et pour aller plus loin, que les deux objets sont les mêmes: ils utilisent le même espace mémoire.

Il semble simple finalement d'utiliser les références en PHP allez-vous dire! En fait, l'exemple que nous venons de voir est un petit exemple. Partons du principe que vous vouliez utiliser deux classes: la classe Utilisateur et la classe Adresse. Voici ce que nous devons écrire en PHP 4 pour utiliser les références:

  1. <?php
  2. class Adresse
  3. {
  4. var $adresse;
  5. var $codepostal;
  6. var $ville;
  7.  
  8. function Adresse($adresse, $codePostal, $ville) {
  9. $this->setAdresse($adresse);
  10. $this->setCodePostal($codePostal);
  11. $this->setVille($ville);
  12. }
  13. function setAdresse($adresse) {
  14. $this->adresse = $adresse;
  15. }
  16. function setCodePostal($codepostal) {
  17. $this->codepostal = $codepostal;
  18. }
  19. function setVille($ville) {
  20. $this->ville = $ville;
  21. }
  22. function getAdresse() {
  23. return($this->adresse);
  24. }
  25. function getCodePostal() {
  26. return($this->codepostal);
  27. }
  28. function getVille() {
  29. return($this->ville);
  30. }
  31. }
  32.  
  33. class Utilisateur
  34. {
  35. var $nom;
  36. var $prenom;
  37. var $email;
  38. var $adresse;
  39.  
  40. function Utilisateur($nom, $prenom, $email, &$adresse) {
  41. $this->setNom($nom);
  42. $this->setPrenom($prenom);
  43. $this->setEmail($email);
  44. $this->setAdresse(&$adresse);
  45. }
  46. function setNom($nom) {
  47. $this->nom = $nom;
  48. }
  49. function setPrenom($prenom) {
  50. $this->prenom = $prenom;
  51. }
  52. function setEmail($email) {
  53. $this->email = $email;
  54. }
  55. function setAdresse(&$adresse) {
  56. $this->adresse =& $adresse;
  57. }
  58. function getNom() {
  59. return($this->nom);
  60. }
  61. function getPrenom() {
  62. return($this->prenom);
  63. }
  64. function getEmail() {
  65. return($this->email);
  66. }
  67. function &getAdresse() {
  68. return($this->adresse);
  69. }
  70. }
  71.  
  72. $adresse =& new Adresse("1, bd de la Paix", "75000", "PARIS");
  73. $utilisateur =& new Utilisateur("MARTIN", "Jean", "jmartin@adressemailbidon.zz", $adresse);
  74.  
  75. // Affichage des données de l'utilisateur
  76. echo("<pre>");
  77. print_r($utilisateur);
  78. echo("</pre><br>\n");
  79.  
  80. // Modification de l'adresse via la classe Utilisateur (obligé de décomposer les modifications)
  81. $adr =& $utilisateur->getAdresse();
  82. $adr->setCodePostal("44000"); // on peut aussi écrire cela avec $utilisateur->adresse->setCodePostal("44000");
  83. $adr->setVille("NANTES"); // on peut aussi écrire cela avec $utilisateur->adresse->setVille("NANTES");
  84. echo("Après modification de l'adresse:<pre>");
  85. print_r($utilisateur);
  86. echo("</pre><br>\n");
  87. ?>

Pour les développeurs qui connaissent le C++ ou Java, ce n'est pas inhabituel. Mais avec PHP 4, il n'est pas possible d'enchaîner les appels comme ceci:

$utilisateur->getAdresse()->setCodePostal("44000");
$utilisateur->getAdresse()->setVille("NANTES");

Il faut impérativement passer par plusieurs étapes en récupérant d'abord l'instance de l'adresse puis en appelant les méthodes de cette adresse. En plus, nous retrouvons des esperluettes un peu "partout" ce qui augmente le risque d'erreurs.

[modifier] Ce que propose PHP 5

PHP 5 propose une approche différentes des objets puisque qu'on ne travaille qu'avec des références (comme en Java par exemple).

Si le développeur déclare une instance de classe, voici ce qu'il a à faire:

  1. <?php
  2. $obj = new MaClasse();
  3. ?>

Et c'est bel et bien une référence sur l'objet que le développeur va manipuler. On n'utilise plus d'esperluette , ce n'est plus nécessaire! Grâce à cela, il y a moins de risques d'erreurs.

Si nous réécrivons le code que nous avions vu dans la partie concernant PHP 4 (avec Utilisateur et Adresse), voici ce que nous aurions en PHP 5:

  1. <?php
  2. class Adresse
  3. {
  4. private $adresse;
  5. private $codepostal;
  6. private $ville;
  7.  
  8. public function setAdresse($adresse) {
  9. $this->adresse = $adresse;
  10. }
  11. public function setCodePostal($codepostal) {
  12. $this->codepostal = $codepostal;
  13. }
  14. public function setVille($ville) {
  15. $this->ville = $ville;
  16. }
  17. public function getAdresse() {
  18. return($this->adresse);
  19. }
  20. public function getCodePostal() {
  21. return($this->codepostal);
  22. }
  23. public function getVille() {
  24. return($this->ville);
  25. }
  26. }
  27.  
  28. class Utilisateur
  29. {
  30. private $nom;
  31. private $prenom;
  32. private $email;
  33. private $adresse;
  34.  
  35. public function setNom($nom) {
  36. $this->nom = $nom;
  37. }
  38. public function setPrenom($prenom) {
  39. $this->prenom = $prenom;
  40. }
  41. public function setEmail($email) {
  42. $this->email = $email;
  43. }
  44. public function setAdresse($adresse) {
  45. $this->adresse = $adresse;
  46. }
  47. public function getNom() {
  48. return($this->nom);
  49. }
  50. public function getPrenom() {
  51. return($this->prenom);
  52. }
  53. public function getEmail() {
  54. return($this->email);
  55. }
  56. public function getAdresse() {
  57. return($this->adresse);
  58. }
  59. }
  60.  
  61. // On définit une adresse que l'on rattache à un utilisateur
  62. $adresse = new Adresse();
  63. $utilisateur = new Utilisateur();
  64. $utilisateur->setAdresse($adresse);
  65.  
  66. // On définit les paramètres de l'utilisateur
  67. $utilisateur->setNom("MARTIN");
  68. $utilisateur->setPrenom("Paul");
  69. $utilisateur->setEmail("paul.martin@adresse-email-bidon.fr");
  70.  
  71. // On définit les paramètres de son adresse
  72. $adresse->setAdresse("1, rue Sésame");
  73. $adresse->setCodePostal(75001);
  74. $adresse->setVille("PARIS");
  75.  
  76. // On affiche le résultat cequi montre bien que l'objet Utilisateur stocke
  77. // la référence sur l'adresse et non la valeur
  78. print_r($utilisateur); echo("<br>\n");
  79.  
  80. // Ceci démondre que comme dans les langages objets évolués, il est
  81. // possible de "chaîner" les appels de méthodes puisque getAdresse retourne
  82. // la référence de l'objet Adresse
  83. $utilisateur->getAdresse()->setCodePostal(75002);
  84. print_r($utilisateur); echo("<br>\n");
  85. ?>

Donc, toutes les esperluettes ont disparu et nous pouvons maintenant enchaîner les appels de méthodes comme nous pourrions le faire en Java. Mais tout ceci n'est pas totalement "innocent" puisque PHP doit se rapprocher petit à petit de Java pour permettre d'utiliser directement les objets Java comme des objets PHP.

[modifier] Historique de l'article

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