Un adapteur générique pour appeler les fonctions natives de PHP

Cet article a été publié depuis plus de 6 mois, cela signifie que le contenu peut ne plus être d'actualité.

L'adaptateur (adapter en anglais) est l'un des design patterns les plus connus et utilisés en programmation. "Il permet de convertir l'interface d'une classe en une autre interface que le client attend. L'adaptateur fait fonctionner ensemble des classes qui n'auraient pas pu fonctionner sans lui, à cause d'une incompatibilité d'interfaces" (définition Wikipedia).

Il ne s'agit ni plus ni moins que d'un proxy qui va se charger de faire des appels d'une classe à un autre en transformant les données dans le format attendu. Les adaptateurs sont très utiles pour l'écriture de tests unitaires car ils permettent au travers de l'injection de dépendances d'être remplacé par un mock. C'est un cas d'utilisation très pratique lorsque l'on souhaite tester des blocs de code faisant appel à des fonctions natives de PHP.

Par exemple, si l'on souhaite lire un fichier de configuration, nous pourrions écrire le code suivant :

public function getUserConfiguration($user, $key)
{
    $configurationFile = file_get_contents($user->getConfigurationFile());

    $configuration = $this->parse($configurationFile);
    return $configuration[$key];
}

Le code ci-dessus pose problème, car il est impossible de contrôler l'exécution de la méthode file_get_contents. Si le test échoue, cela ne sera pas forcément lié au code qui a été écrit, mais peut-être au système de fichiers qui est indisponible au moment du test.

On peut alors écrire le test en utilisant un adaptateur :

public function getUserConfiguration($user, $key)
{
    $configurationFile = $this->fileAdapter->getFileContent($user->getConfigurationFile());

    $configuration = $this->parse($configurationFile);
    return $configuration[$key];
}

De cette manière, le code devient facilement testable, puisqu'il suffira d'utiliser un mock de la classe fileAdapter implémentant la méthode getFileContent.

C'est d'ailleurs en jetant un oeil dans le code source d'Atoum, un framework de tests unitaires (que je recommande vivement) que j'ai découvert un adaptateur générique permettant de tester naturellement les fonctions natives de PHP (également présenté dans un très bon article de Julien BIANCHI).

Voici le code de l'adaptateur :

// disponible à l'URL suivante => https://github.com/atoum/atoum/blob/master/classes/adapter.php
class adapter
{
    public function __call($functionName, $arguments)
    {
        return $this->invoke($functionName, $arguments);
    }

    public function invoke($functionName, array $arguments = array())
    {
        return call_user_func_array($functionName, $arguments);
    }
}

Cette classe est très astucieuse et fait appel "aux méthodes magiques" de PHP afin de rediriger les appels de l'adaptateur vers les fonctions natives du langage. De cette manière, plus besoin de créer une multitude de classes adaptateurs pour garantir que l'ensemble de notre code soit testable unitairement.

Attention toutefois à ne pas en abuser, les adaptateurs comme tout principe de programmation doivent être utilisé de manière judicieuse.