[php5] factory et paramètres constructeurs

Contenu du snippet

Lorsque l'on utilise une gestion modulaire (par exemple un système de Factory), et que l'on charge dynamiquement les classes, il est plutôt usuel de leur passer en paramètre un tableu de configuration :
return new $className($config);
Seulement, il arrive peut-être des fois où l'on veut intégrer une classe déjà existante que, elle, prends quelques paramètres. Il n'est certes pas difficile du tout de réécrire le bout de code faisant en sorte que le tout soit géré dans un array, mais je pense qu'il est globalement mieux d'avoir une liste de paramètres. D'autant plus que celà oblige à passer le nombre exact de paramètres, sinon PHP renvoie une erreur. Avec un array, il faut nous même gêrer ça... Et comme les informaticiens programment plus pour en faire le moins possible après, je pense que ce code a sa place ici :)
Pour ceux qui ne connaissent pas, voici deux liens :
http://en.wikipedia.org/wiki/Reflection_%28computer_science%29 (ou http://fr.wikipedia.org/wiki/R%C3%A9flexion_%28informatique%29 , mais moins complet ... )
http://php.net/reflection

Pour faire simple, la réflection, c'est la capacité d'un programme à analyser son état, où à se modifier lui-même.
Il est par exemple possible, en javascript, de modifier le comportemt d'une fonction :
http://en.wikipedia.org/wiki/Self-modifying_code#Example_JavaScript_self-modifying_code

Bref, il n'est pas question ici de modifier le comportement d'une fonction ( il existe d'ailleurs runkit pour ça pour le moment [Même si ça ne vaut pas la réflexion] : http://php.net/runkit ), mais tout simplement de faire appel à une fonction de l'API de réflexion pour instancier notre classe.

Voir le code ci-dessous.

Source / Exemple :


<?php

class MySQL
{
	function __construct($sBdd, $sUser, $sPass)
	{
		echo '<strong>Paramètres :</strong> ' . $sBdd . '/' . $sUser . '/' . $sPass . '<br />';
	}
}

class Postgresql
{
    function __construct($sConnextionString)
    {
        echo '<strong>Paramètres :</strong> ' . $sConnextionString . '<br />';
    }
}

class Factory
{
	private static $_aInstances = array();

	public static function createInstance($sClassName, $mArgs)
	{
		if (!isset(self::$_aInstances[$sClassName]))
		{
			if (class_exists($sClassName))
			{
				$oClass = new ReflectionClass($sClassName);
				if (is_array($mArgs))
				{
					self::$_aInstances[$sClassName] = $oClass->newInstanceArgs($mArgs);
				}
				else if ($mArgs)
				{
					self::$_aInstances[$sClassName] = $oClass->newInstance($mArgs);
				}
				else
				{
					self::$_aInstances[$sClassName] = $oClass->newInstance();
				}
			}
			else
			{
				throw new Exception('La classe ' . $sClassName . ' n\'existe pas !');
			}
		}
		return self::$_aInstances[$sClassName];
	}
}

try
{
	$oMySQL = Factory::createInstance('MySQL', array('bdd.exemple.com', 'MyUser', 'MyPass'));
	echo '<strong>$oMySQL</strong> est une instance de la classe : ' . get_class($oMySQL) . '<br />';
	$oPgsql = Factory::createInstance('Postgresql', 'host=bdd.exemple.com dbname=test user=MyUser password=MyPass');
	echo '<strong>$oPgsql</strong> est une instance de la classe : ' . get_class($oPgsql) . '<br />';
}
catch (Exception $e)
{
	echo $e->getMessage();
}

?>

Conclusion :


Bon j'aurais aussi pu remplacer :
///
if (is_array($mArgs))
{
self::$_aInstances[$sClassName] = $oClass->newInstanceArgs($mArgs);
}
else
{
self::$_aInstances[$sClassName] = $oClass->newInstance($mArgs);
}
\\\

Par

///
$newFunction = (is_array($mArgs) ? 'newInstanceArgs' : 'newInstance');
self::$_aInstances[$sClassName] = $oClass->$newFunction($mArgs);
\\\

Ah, et le code du Factory a été très largement inspiré par cette source, merci à l'auteur :
http://www.phpcs.com/codes/PHP5-COUCHE-ABSTRACTION-SGBD_35488.aspx

Have fun :)
Mais j'ai préféré garder le code lisible pour que tout le monde puisse comprendre :)

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.