Facebook LinkedIn SourceForge Twitter RSS LastFM
logologo

Comment utiliser un objet PHP sans le déclarer ?

Geoffray Warnants|19/10/2008|6 commentaires

Pour illustrer ce que je voulais pouvoir faire en PHP, je me suis inspiré du langage Java où on rencontre parfois ce genre d'appel :
// en Java
new Application(login, pwd).start();
La particularité est qu'on peut utiliser un objet sans avoir forcément besoin de le déclarer dans une variable. Ceci est souvent utilisé dans le cas où cet objet n'est nécessaire qu'à un unique endroit du programme. Malheureusement, PHP n'autorise pas cette syntaxe, ce qui nous contraint de scinder l'opération et de s'encombrer d'une variable intermédiaire qui nous est inutile.
// en PHP
$app = new Application($login, $pwd);
$app->start();
unset($app);

L'avantage de la première solution, outre le fait apprécié qu'elle offre une écriture plus concise, réside dans la mise en évidence de l'inutilité de l'instance en dehors de cet unique appel, ce qui peut s'avérer d'une grande utilité pour une compréhension rapide du code par un tierce développeur.

Pour pouvoir reproduire cette écriture en PHP, j'ai créé la petite classe suivante (qui aurait très bien pu n'être qu'une simple fonction) :
class ClassLoader {
    public static function load($className, $arg=null) {
        $c = new ReflectionClass($className);
        return ($c->hasMethod('__construct') || $c->hasMethod($className)) ?
            $c->newInstanceArgs(array_splice(func_get_args(), 1)) :
            $c->newInstance();
    }
}
On peut alors écrire :
ClassLoader::load('Application', $login, $pwd)->start();
Le principe devient intéressant, mais la clarté du code en a pris un sacré coup ! Pour simplifier, j'ai pensé à une nouveauté très attendue de PHP 5.3 : la nouvelle méthode magique __callStatic, dont le comportement est identique à la méthode __call bien connue, mais adaptée aux méthodes statiques.
// à partir de PHP 5.3
class ClassLoader {
    public static function __callStatic($method, $args) {
        $c = new ReflectionClass($method);
        return ($c->hasMethod('__construct') || $c->hasMethod($method)) ?
            $c->newInstanceArgs($args) :
            $c->newInstance();
    }
}    
L'écriture gagne ainsi nettement en simplicité :
ClassLoader::Application($login, $pwd)->start();
Il ne reste plus qu'à finaliser la classe pour la rendre compatible PHP 5 et 6, ce qui ne pose pas de problème. Il sera juste laissé au développeur le soin de réaliser les appels adéquats selon la version de PHP utilisée, avec la seule petite restriction qu'en PHP 6, le chargement d'une éventuelle classe nommée "Load" devra inévitablement se faire via l'écriture PHP 5.
class ClassLoader {
    public static function load($className, $arg=null) {
        $c = new ReflectionClass($className);
        return ($c->hasMethod('__construct') || $c->hasMethod($className)) ?
            $c->newInstanceArgs(array_splice(func_get_args(), 1)) :
            $c->newInstance();
    }
    
    public static function __callStatic($className, $args) {
        return call_user_func_array(
            array(self, 'load'), array_merge(array($className),$args)
        );
    }
}

<<< Retour

Vos commentaires

3 commentaires postés

Matthieu
16/06/2009 18:56Posté par Matthieu
Je propose tout simplement de créer une methode statique dans ta classe qui retourne une instance de la classe. ex :

<?php
// La class
class MaClass
{
private function __construct()
{

}

public static function init()
{
return new MaClass();
}

public function start()
{

}
}

// Utilisation
MaClass::init()->start();
?>

Non ?
Geoffray
05/02/2009 22:04Posté par Geoffray
Tout à fait d'accord pour dire que la Réflexion ne soit pas une solution des plus performantes et que le bénéfice apporté par tout ce mécanisme ne soit pas des plus utiles. La démarche était plutôt destinée à explorer les possibilités pour éviter l'affectation de variable... sans grand succès.
John
03/02/2009 15:44Posté par John
Et pourquoi ne pas déclarer ta méthode start() comme static dans ta classe ?

Si son comportement est tel qu'elle peut être utilisée hors de l'instanciation de la classe à  laquelle elle appartient, elle n'a pas de raison d'être déclarée autrement.

La solution qui consiste à utiliser la Reflexion est tellement lourde d'un point de vue compréhension du code et utilisation mémoire.

Appeller et utiliser tout une gestion de classe pour éviter une affection de variable...

Réagir à cet article

*


(Ne sera pas publiée, servira uniquement à afficher votre gravatar)


(Lien en dur et dofollow)

zend framework