dimanche 13 juin 2010

Comment supporter __construct() et __destruct() en PHP 4 ?

Ok, rien à voir avec la sécurité, le Reverse Code Engineering ou quoi, mais je m'en fous. C'est mon blog et j'ai bien prévenu que je pouvais publier des trucs sur les polly pockets et les figurines en castor.

Allez, plus sérieusement, j'aimerais partager une astuce - m'en souvenir aussi, en tout cas - de programmation orientée objet en php. Je signale que cette méthode n'est en rien issu d'une masturbation intellectuelle, j'ai trouvé ça dans le framework CakePHP.

Pour se situer dans le contexte



En php4, voici ce qu'on ferait pour déclarer notre définition de classe (le moule à gateau, quoi).

<?php

class Foo {
private $_param = null;

/* Constructeur de la classe */
public function Foo($arg = "") {
$this->_param = $arg;
}
}



Notez que j'ai omis le "?>" à la fin ; en effet, ça permet d'éviter d'avoir des erreurs à la con genre "header already sent by "fichier.class.php" on line [...]. On est sûr de n'avoir que du PHP derrière, pas d'echo d'HTML ni rien.

Et donc, en PHP 5, on a ça :

<?php

class Foo {
private $_param = null;

/* Constructeur de la classe */
public function __construct($arg = "") {
$this->_param = $arg;
}
}



On se sert de la méthode magique __construct(). Notez qu'on peut très bien utiliser aussi le constructeur "Foo()", mais les méthodes magiques n'ont pas été conçues pour rien !

Et pour preuve, en PHP 5, on peut faire ça :

<?php

class Foo {
private $_param = null;

/* Constructeur de la classe */
public function __construct($arg = "") {
$this->_param = $arg;
}

/* Destructeur de la classe */
public function __destruct() {
echo "Bye bye!\n";
}
}



Généralement, on utilise les destructeurs lorsque notre objet est amené à allouer des ressources dynamiquement ; il faut donc les libérer.

Prenons un exemple con : un objet va encapsuler un fichier. Le constructeur va ouvrir ce fichier (ça sera transparent) et le destructeur le fermera sans que nous ayons à écrire :

fclose($handleSurNotreFichier);


Bref, revenons à nos moutons. On est passé à PHP 5 dans la plupart des cas, mais il arrive parfois qu'on ne dispose que d'une version 4 qui ne supporte pas __construct() et __destruct() comme on le souhaiterait. En effet, ces méthodes ne seraient pas magiques et donc pas appelées automatiquement et respectivement lors de la construction et la destruction d'une instance.

Voici comment CakePHP procède : tout d'abord, il définit une class "Mère", je dirais même "Doyenne" donc toutes les autres classes hériteront. Et là, vous comprendrez vite l'intention :

<?php

class Mother {

public function Mother() {
/* On récupère les arguments passés à la fonction
via http://fr.php.net/func_get_args */
$arguments = func_get_args();

/* On vérifie si la méthode __destruct() existe
via http://fr2.php.net/method_exists */
if(method_exists($this, "__destruct")) {
/* Si c'est le cas, on l'assimile en fonction
"callback" de "shutdown, c'est-à-dire qu'elle
sera appelée en fin de vie de l'instance
(http://fr2.php.net/register_shutdown_function)
*/
register_shutdown_function( array(&$this, "__destruct") );
}
/* On appelle notre méthode __construct() avec les arguments passés
avec http://fr2.php.net/call_user_func_array */
call_user_func_array(array(&$this, "__construct"), $arguments);
}

/* Et là, on a notre constructeur qui sera surchargé par les classes
filles */
public function __construct() {
/* Le code de votre choix */
}
}


Désormais, qu'on soit en PHP 4 ou PHP 5, on pourra faire :

<?php

class MaClasse extends Mother {

/* Handle sur un fichier */
private $_handle = null;

/* Constructeur */
public function __construct() {
/* Ouverture d'un fichier */
$this->_handle = @fopen("fichier", "w");
}

/* On peut imaginer des méthodes pour écrire, tout effacer, etc... */

/* Destructeur */
public function __destruct() {
fclose($this->_handle);
}
}


Si ça se trouve j'étais le seul à pas connaître ce tour de passe-passe (& puis tant mieux) mais si y'en a à qui ça peut servir, ben tant mieux. J'ai aucun mérite sur la chose, mais je me dis que partager cette petite astuce qui se retrouve au milieu d'un bazar pointu - c'est comme auditer le code de phpBB, quoi - pourrait servir...

Geo

3 commentaires:

  1. Super article.
    Merci!

    PS : Si tu as un peu de temps extra, visites mon blog a cette adresse :
    www.aut4n.wordpress.co

    Salut!

    RépondreSupprimer
  2. Sympa, cool, article geo0w.
    Agréable à lire.

    Shoot moi une visite ici :
    http://0x04h.blogspot.com/

    a+

    RépondreSupprimer
  3. Ton blog ne fonctionne pas, est-ce normal ?

    RépondreSupprimer