- 95% des demandes d'aide de nos clients sont traités en moins de 2 heures !
- Nous sommes toujours en pleine innovation !
- Nous améliorons sans cesse la qualité de nos services !
PHP 5 introduit API de réflexion complète qui permet de faire du
reverse-engineering sur les classes, les interfaces,
les fonctions et les méthodes tout comme les extensions. L'API de
réflexion permet également d'obtenir les commentaires de la documentation
pour les fonctions, les classes et les méthodes.
L'API de réflexion est une extension orientée objet du Moteur Zend,
constituée des classes suivantes :
<?php class Reflection { } interface Reflector { } class ReflectionException extends Exception { } class ReflectionFunction extends ReflectionFunctionAbstract implements Reflector { } class ReflectionParameter implements Reflector { } class ReflectionMethod extends ReflectionFunctionAbstract implements Reflector { } class ReflectionClass implements Reflector { } class ReflectionObject extends ReflectionClass { } class ReflectionProperty implements Reflector { } class ReflectionExtension implements Reflector { } ?>
Note:
Pour plus de détails sur ces classes, lisez les chapitres suivants.
Si nous exécutons le code de l'exemple ci-dessous :
Exemple #1 Utilisation basique de l'API de réflexion
Reflector est une interface implémentée
par toutes les classes exportables de réflection.
<?php interface Reflector { public string __toString() public static string export() } ?>
ReflectionException
ReflectionException étend le standard
Exception et est lancé
par l'API Reflection. Aucune méthode spécifique ni de propriété
ne sont introduites.
ReflectionFunction
La classe ReflectionFunction vous permet de faire
du reverse-engineering sur les fonctions.
<?php class ReflectionFunction extends ReflectionFunctionAbstract implements Reflector { final private __clone() public void __construct(string name) public string __toString() public static string export(string name, bool return) public string getName() public bool isInternal() public bool isDisabled() public mixed getClosure() /* Depuis PHP 5.3.0 */ public bool isUserDefined() public string getFileName() public int getStartLine() public int getEndLine() public string getDocComment() public array getStaticVariables() public mixed invoke([mixed args [, ...]]) public mixed invokeArgs(array args) public bool returnsReference() public ReflectionParameter[] getParameters() public int getNumberOfParameters() public int getNumberOfRequiredParameters() } ?>
La classe parent ReflectionFunctionAbstract a les mêmes méthodes,
exceptée invoke(), invokeArgs(),
export() et isDisabled().
Note:
getNumberOfParameters() et
getNumberOfRequiredParameters() ont été ajoutés en PHP
5.0.3, tandis que invokeArgs() a été ajouté en PHP 5.1.0.
Pour connaître le fonctionnement d'une fonction, vous devez tout d'abord
créer une instance de la classe ReflectionFunction.
Ainsi, vous pouvez appeler n'importe quelle méthode de cette instance.
Exemple #2 Utilisation de la classe ReflectionFunction
<?php /** * Un simple compteur * * @return int */ function counter() { static $c = 0; return $c++; }
// Création d'une instance de la classe ReflectionFunction $func = new ReflectionFunction('counter');
// Affichage d'informations basiques printf( "===> The %s function '%s'\n". " declared in %s\n". " lines %d to %d\n", $func->isInternal() ? 'internal' : 'user-defined', $func->getName(), $func->getFileName(), $func->getStartLine(), $func->getEndline() );
// Affichage du commentaire de la documentation printf("---> Documentation:\n %s\n", var_export($func->getDocComment(), 1));
// Affichage des variables statiques si elles existent if ($statics = $func->getStaticVariables()) { printf("---> Variables statiques : %s\n", var_export($statics, 1)); }
// Appel de la fonction printf("---> Invocation des résultats dans : "); var_dump($func->invoke());
// vous pouvez préférer utiliser la méthode export() echo "\nRésultat de ReflectionFunction::export() :\n"; echo ReflectionFunction::export('counter'); ?>
Note:
La méthode invoke() accepte un nombre variable
d'arguments, tout comme la fonction
call_user_func().
ReflectionParameter
La classe ReflectionParameter récupère les
informations concernant les paramètres des fonctions ou des méthodes.
<?php class ReflectionParameter implements Reflector { final private __clone() public void __construct(string function, string parameter) public string __toString() public static string export(mixed function, mixed parameter, bool return) public string getName() public bool isPassedByReference() public ReflectionClass getDeclaringClass() public ReflectionClass getClass() public bool isArray() public bool allowsNull() public bool isPassedByReference() public bool isOptional() public bool isDefaultValueAvailable() public mixed getDefaultValue() public int getPosition() } ?>
Note:
getDefaultValue(),
isDefaultValueAvailable() et
isOptional() ont été ajoutés en PHP 5.0.3,
tandis que isArray() a été ajoutée en PHP 5.1.0.
getDeclaringFunction() et
getPosition() ont été ajoutés en PHP 5.2.3.
Pour connaître le fonctionnement des paramètres d'une fonction, vous
devez tout d'abord créer une instance de la classe
ReflectionFunction ou
ReflectionMethod et, ainsi, utiliser leurs méthodes
getparameters() pour récupérer un tableau de paramètres.
Exemple #3 Utilisation de la classe ReflectionParameter
<?php function foo($a, $b, $c) { } function bar(Exception $a, &$b, $c) { } function baz(ReflectionFunction $a, $b = 1, $c = null) { } function abc() { }
// Création d'une instance de la classe ReflectionFunction avec le // paramètre fourni en ligne de commande. $reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param) { printf( "-- Paramètre #%d : %s {\n". " Classe : %s\n". " Autorise NULL : %s\n". " Passé par référence : %s\n". " Est optionnel ?: %s\n". "}\n", $i, // $param->getPosition() peut être utilisé depuis PHP 5.2.3 $param->getName(), var_export($param->getClass(), 1), var_export($param->allowsNull(), 1), var_export($param->isPassedByReference(), 1), $param->isOptional() ? 'oui' : 'non' ); } ?>
ReflectionClass
La classe ReflectionClass vous permet
de faire du reverse-engineering sur des classes
et des interfaces.
<?php class ReflectionClass implements Reflector { final private __clone() public void __construct(string name) public string __toString() public static string export(mixed class, bool return) public string getName() public bool isInternal() public bool isUserDefined() public bool isInstantiable() public bool hasConstant(string name) public bool hasMethod(string name) public bool hasProperty(string name) public string getFileName() public int getStartLine() public int getEndLine() public string getDocComment() public ReflectionMethod getConstructor() public ReflectionMethod getMethod(string name) public ReflectionMethod[] getMethods() public ReflectionProperty getProperty(string name) public ReflectionProperty[] getProperties() public array getConstants() public mixed getConstant(string name) public ReflectionClass[] getInterfaces() public bool isInterface() public bool isAbstract() public bool isFinal() public int getModifiers() public bool isInstance(stdclass object) public stdclass newInstance(mixed args) public stdclass newInstanceArgs(array args) public ReflectionClass getParentClass() public bool isSubclassOf(ReflectionClass class) public array getStaticProperties() public mixed getStaticPropertyValue(string name [, mixed default]) public void setStaticPropertyValue(string name, mixed value) public array getDefaultProperties() public bool isIterateable() public bool implementsInterface(string name) public ReflectionExtension getExtension() public string getExtensionName() } ?>
Note:
hasConstant(), hasMethod(),
hasProperty(), getStaticPropertyValue()
et setStaticPropertyValue() ont été ajoutées en PHP
5.1.0, tandis que newInstanceArgs() a été ajoutée dans
PHP 5.1.3.
Pour connaître le fonctionnement d'une classe, vous devez d'abord créer
une instance de la classe ReflectionClass. Vous
pourrez donc appeler n'importe quelle méthode sur cette instance.
Exemple #4 Utilisation de la classe ReflectionClass
<?php interface Linearisable { // ... }
class Object { // ... }
/** * Une classe compteur */ class Compteur extends Object implements Linearisable { const START = 0; private static $c = Compteur::START;
/** * Invocation du compteur * * @access public * @return int */ public function count() { return self::$c++; } }
// Création d'une instance de la classe ReflectionClass $class = new ReflectionClass('Compteur');
echo "\n---> Le nouvel objet Object() est une instance ? "; echo $class->isInstance(new Object()) ? 'oui' : 'non'; } ?>
Note:
La méthode newinstance() accepte un nombre variable
d'arguments, tout comme la fonction
call_user_func().
Note:
$class = new ReflectionClass('Foo');
$class->isInstance($arg)
est équivalent à $arg instanceof Foo ou
is_a($arg, 'Foo').
ReflectionObject
La classe ReflectionObject vous permet
de retrouver les objets.
<?php class ReflectionObject extends ReflectionClass { final private __clone() public void __construct(mixed object) public string __toString() public static string export(mixed object, bool return) } ?>
ReflectionMethod
La classe ReflectionMethod vous permet de faire du
reverse-engineering sur les méthodes des classes.
<?php class ReflectionMethod extends ReflectionFunctionAbstract implements Reflector { public void __construct(mixed class, string name) public string __toString() public static string export(mixed class, string name, bool return) public mixed invoke(stdclass object [, mixed args [, ...]]) public mixed invokeArgs(stdclass object, array args) public bool isFinal() public bool isAbstract() public bool isPublic() public bool isPrivate() public bool isProtected() public bool isStatic() public bool isConstructor() public bool isDestructor() public int getModifiers() public mixed getClosure() /* Depuis PHP 5.3.0 */ public ReflectionClass getDeclaringClass()
// Inherited from ReflectionFunctionAbstract final private __clone() public string getName() public bool isInternal() public bool isUserDefined() public string getFileName() public int getStartLine() public int getEndLine() public string getDocComment() public array getStaticVariables() public bool returnsReference() public ReflectionParameter[] getParameters() public int getNumberOfParameters() public int getNumberOfRequiredParameters() } ?>
Pour connaître le fonctionnement d'une méthode, vous devez d'abord créer
une instance de la classe ReflectionMethod. Vous
pourrez ainsi appeler n'importe quelle méthode de cette instance.
Exemple #5
Utilisation de la classe ReflectionMethod
<?php class Compteur { private static $c = 0;
/** * Incrémentation d'un compteur * * @final * @static * @access public * @return int */ final public static function increment() { return self::$c; } }
// Création d'une instance de la classe ReflectionMethod $method = new ReflectionMethod('Compteur', 'increment');
// Affichage d'informations basiques printf( "===> La méthode %s%s%s%s%s%s%s '%s' (qui est %s)\n". " déclaré dans %s\n". " lignes %d à %d\n". " a les modificateurs %d[%s]\n", $method->isInternal() ? 'internal' : 'user-defined', $method->isAbstract() ? ' abstract' : '', $method->isFinal() ? ' final' : '', $method->isPublic() ? ' public' : '', $method->isPrivate() ? ' private' : '', $method->isProtected() ? ' protected' : '', $method->isStatic() ? ' static' : '', $method->getName(), $method->isConstructor() ? 'the constructor' : 'a regular method', $method->getFileName(), $method->getStartLine(), $method->getEndline(), $method->getModifiers(), implode(' ', Reflection::getModifierNames($method->getModifiers())) );
// Affichage du commentaire de la documentation printf("---> Documentation:\n %s\n", var_export($method->getDocComment(), 1));
// Affichage des variables statiques si elles existent if ($statics= $method->getStaticVariables()) { printf("---> Variales statiques : %s\n", var_export($statics, 1)); }
// Invocation de la méthode printf("---> Résultat de l'invocation dans : "); var_dump($method->invoke(NULL)); ?>
Exemple #6 Obtention d'une clôture en utilisant la classe ReflectionMethod
<?php
class Exemple { static function printer () { echo "Bonjour le Monde!\n"; } }
$class = new ReflectionClass('Exemple'); $method = $class->getMethod('printer'); $closure = $method->getClosure(); /* Depuis PHP 5.3.0 */ $closure(); // Bonjour le Monde!
?>
Note:
Invoquer des méthodes privées, protégées ou abstraites provoquera
une exception jetée par la méthode invoke().
Note:
Pour les méthodes statiques comme vu précédemment, vous devez passer
NULL comme premier argument à la fonction invoke().
Pour les méthodes non-statiques, passez une instance de la classe.
ReflectionProperty
La classe ReflectionProperty vous permet
de faire du reverse-engineering sur les propriétés des
classes.
<?php class ReflectionProperty implements Reflector { final private __clone() public void __construct(mixed class, string name) public string __toString() public static string export(mixed class, string name, bool return) public string getName() public bool isPublic() public bool isPrivate() public bool isProtected() public bool isStatic() public bool isDefault() public void setAccessible() /* Depuis PHP 5.3.0 */ public int getModifiers() public mixed getValue(stdclass object) public void setValue(stdclass object, mixed value) public ReflectionClass getDeclaringClass() public string getDocComment() } ?>
Note:
getDocComment() a été ajouté en PHP 5.1.0.
setAccessible() a été ajouté en PHP 5.3.0.
Pour connaître le fonctionnement d'une propriété, vous devez d'abord créer
une instance de la classe ReflectionProperty. Vous
pourrez ainsi appeler n'importe quelle méthode de cette instance.
Exemple #7
Utilisation de la classe ReflectionProperty
<?php class Chaine { public $length = 5; }
// Création d'une instance de la classe ReflectionProperty $prop = new ReflectionProperty('Chaine', 'length');
// Affichage d'informations basiques printf( "===> Les propriétés %s%s%s%s '%s' (qui a %s)\n". " a les modificateurs %s\n", $prop->isPublic() ? ' public' : '', $prop->isPrivate() ? ' private' : '', $prop->isProtected() ? ' protected' : '', $prop->isStatic() ? ' static' : '', $prop->getName(), $prop->isDefault() ? 'déclaré au moment de la compilation' : 'créé au moment de l\'exécution', var_export(Reflection::getModifierNames($prop->getModifiers()), 1) );
// Création d'une instance de Chaine $obj= new Chaine();
// Récupération de la valeur courante printf("---> La veleur est : "); var_dump($prop->getValue($obj));
// Modification de la valeur $prop->setValue($obj, 10); printf("---> Définition de la valeur à 10, la nouvelle valeur est : "); var_dump($prop->getValue($obj));
// Affichage de l'objet var_dump($obj); ?>
Exemple #8 Obtenir la valeur d'une propriété privée et protégée en utilisant la classe ReflectionProperty
<?php
class Foo { public $x = 1; protected $y = 2; private $z = 3; }
$obj = new Foo;
$prop = new ReflectionProperty('Foo', 'y'); $prop->setAccessible(true); /* Depuis PHP 5.3.0 */ var_dump($prop->getValue($obj)); // int(2)
$prop = new ReflectionProperty('Foo', 'z'); $prop->setAccessible(true); /* Depuis PHP 5.3.0 */ var_dump($prop->getValue($obj)); // int(2)
?>
Note:
Essayer de récupérer ou de définir les valeurs des propriétés d'une classe
privée ou protégée produira une exception.
ReflectionExtension
La classe ReflectionExtension vous permet de faire du
reverse-engineering sur les extensions. Vous pouvez
connaître toutes les extensions chargées à l'exécution en utilisation la
fonction get_loaded_extensions().
<?php class ReflectionExtension implements Reflector { final private __clone() public void __construct(string name) public string __toString() public static string export(string name, bool return) public string getName() public string getVersion() public ReflectionFunction[] getFunctions() public array getConstants() public array getINIEntries() public ReflectionClass[] getClasses() public array getClassNames() public string info() } ?>
Pour connaître le fonctionnement d'une extension, vous devez d'abord créer
une instance de la classe ReflectionExtension. Vous
pourrez ainsi appeler n'importe quelle méthode sur cette instance.
Exemple #9 Utilisation de la classe ReflectionExtension
<?php // Création d'une instance de la classe ReflectionExtension $ext = new ReflectionExtension('standard');
Dans le cas où vous voudriez créer des versions spéciales des classes
embarquées (par exemple pour créer du HTML colorisé lorsqu'il est exporté,
pour avoir un accès facile aux variables des membres au lieu des méthodes ou
pour avoir des méthodes utiles), vous devez étendre la classe.
Exemple #10 Extension des classes embarquées
<?php /** * Ma classe Reflection_Method */ class My_Reflection_Method extends ReflectionMethod { public $visibility = array();
public function __construct($o, $m) { parent::__construct($o, $m); $this->visibility = Reflection::getModifierNames($this->getModifiers()); } }
/** * Démo classe #1 * */ class T { protected function x() {} }
/** * Démo classe #2 * */ class U extends T { function x() {} }
// Affichage des informations var_dump(new My_Reflection_Method('U', 'x')); ?>
Note:
Attention : si vous écrasez le constructeur, n'oubliez
pas d'appeler le constructeur parent avant d'insérer
le moindre code. Sinon, votre code produira l'erreur suivante :
Fatal error: Internal error: Failed to retrieve the reflection object