Php 5 bringt eine komplette Reflection API mit, die Möglichkeiten bietet, um
Klassen, Interfaces, Funktionen und Methoden ebenso wie auch Extensions
zurückzuentwickeln. Zusätzlich bietet die Reflection API Wege,
dokumentarische Kommentare von Funktionen, Klassen und Methoden abzufragen.
Die Refelection API ist eine objektorientierte Erweiterung der Zend Engine,
bestehend aus den folgenden Klassen:
Anmerkung:
Für detailierte Erläuterungen dieser Klassen werfen Sie einen Blick auf die
nächsten Kapitel.
Wenn wir den unten stehenden Beispielcode ausführen würden:
Beispiel 19-33. Grundlegende Nutzung der Reflection API
<?php Reflection::export(new ReflectionClass('Exception')); ?>
|
Das oben gezeigte Beispiel erzeugt folgende
Ausgabe: Class [ <internal> class Exception ] {
- Constants [0] {
}
- Static properties [0] {
}
- Static methods [0] {
}
- Properties [6] {
Property [ <default> protected $message ]
Property [ <default> private $string ]
Property [ <default> protected $code ]
Property [ <default> protected $file ]
Property [ <default> protected $line ]
Property [ <default> private $trace ]
}
- Methods [9] {
Method [ <internal> final private method __clone ] {
}
Method [ <internal> <ctor> public method __construct ] {
- Parameters [2] {
Parameter #0 [ <required> $message ]
Parameter #1 [ <required> $code ]
}
}
Method [ <internal> final public method getMessage ] {
}
Method [ <internal> final public method getCode ] {
}
Method [ <internal> final public method getFile ] {
}
Method [ <internal> final public method getLine ] {
}
Method [ <internal> final public method getTrace ] {
}
Method [ <internal> final public method getTraceAsString ] {
}
Method [ <internal> public method __toString ] {
}
}
} |
|
ReflectionException erweitert die normale
Exception und wird von der
Reflection API geworfen. Es werden keine spezifischen Methoden oder
Eigenschaften eingeführt.
Die ReflectionFunction Klasse lässt Sie
Funktionen zurückentwickeln.
Anmerkung:
getNumberOfParameters() und
getNumberOfRequiredParameters() wurden in PHP
5.0.3 hinzugefügt, während invokeArgs() in PHP 5.1.0
neu hinzukam.
Um einen Blick in eine Funktion zu werfen, muss man erst eine Instanz der Klasse
ReflectionFunction erzeugen. Danach kann man jede
der oben aufgeführten Methoden dieser Instanz aufrufen.
Beispiel 19-34. Die ReflectionFunction Klasse benutzen
<?php /** * Ein einfacher Zähler * * @return int */ function counter() { static $c = 0; return $c++; }
// Erzeuge eine neue Instanz der ReflectionFunction Klasse $func = new ReflectionFunction('counter');
// Grundlegende Informationen ausgeben printf( "===> Die %s Funktion '%s'\n". " ist deklariert in %s\n". " Zeilen %d bis %d\n", $func->isInternal() ? 'interne' : 'benutzerdefinierte', $func->getName(), $func->getFileName(), $func->getStartLine(), $func->getEndline() );
// Dokumentaischen Kommentar ausgeben printf("---> Dokumentation:\n %s\n", var_export($func->getDocComment(), 1));
// Statische Variablen ausgeben, wenn welche existieren if ($statics = $func->getStaticVariables()) { printf("---> Statische Variablen: %s\n", var_export($statics, 1)); }
// Die Funktion aufrufen printf("---> Der Aufruf gibt zurück: "); var_dump($func->invoke());
// Sie könnten bevorzugen die export() Methode zu verwenden echo "\nReflectionFunction::export() gibt zurück:\n"; echo ReflectionFunction::export('counter'); ?>
|
|
Anmerkung:
Die Methode invoke() akzeptiert eine variable Anzahl
von Argumenten, welche genau wie von call_user_func()
an die Funktion übergeben werden.
Die ReflectionParameter Klasse frägt Informationen
über die Parameter einer Funktion oder Methode ab.
Anmerkung:
getDefaultValue(),
isDefaultValueAvailable() und
isOptional() wurden in PHP 5.0.3 hinzugefügt,
während isArray() in PHP 5.1.0 neu ist.
getDeclaringFunction() und
getPosition() wurden in PHP 5.1.3 hinzugefügt.
Um einen Blick in Funktionsparameter zu werfen, muss man zuerst eine Instanz
der Klassen ReflectionFunction oder
ReflectionMethod erzeugen und kann dann deren
getParameters() Methode verwenden, um ein Array ihrer
Parameter abzufragen.
Beispiel 19-35. Die ReflectionParameter Klasse verwenden
<?php function foo($a, $b, $c) { } function bar(Exception $a, &$b, $c) { } function baz(ReflectionFunction $a, $b = 1, $c = null) { } function abc() { }
// Erzeuge eine Instanz von ReflectionFunction mit dem // auf der Kommandozeile übergebenen Parameter $reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param) { printf( "-- Parameter #%d: %s {\n". " Klasse: %s\n". " Erlaubt NULL: %s\n". " Als Referenz übergeben: %s\n". " Ist optional?: %s\n". "}\n", $i, $param->getName(), var_export($param->getClass(), 1), var_export($param->allowsNull(), 1), var_export($param->isPassedByReference(), 1), $param->isOptional() ? 'ja' : 'nein' ); } ?>
|
|
Die ReflectionClass Klasse erlaubt es, Klassen
zurückzuentwickeln.
Anmerkung:
hasConstant(), hasMethod(),
hasProperty(), getStaticPropertyValue()
und setStaticPropertyValue() wurden in PHP 5.1.0
hinzugefügt, während newInstanceArgs() in PHP 5.1.3 dazu
kam.
Um einen Blick in eine Klasse zu werfen, muss man zuerst eine Instanz der
Klasse ReflectionClass erzeugen. Man kann danach jede
der oben angeführten Methoden der Instanz verwenden.
Beispiel 19-36. Die ReflectionClass Klasse verwenden
<?php interface Serializable { // ... }
class Object { // ... }
/** * Eine Zählerklasse */ class Counter extends Object implements Serializable { const START = 0; private static $c = Counter::START;
/** * Zähler aufrufen * * @access public * @return int */ public function count() { return self::$c++; } }
// Eine Instanz der Klasse ReflectionClass erzeugen $class = new ReflectionClass('Counter');
// Grundlegende Informationen ausgeben printf( "===> %s%s%s %s '%s' [extends %s]\n" . " deklariert in %s\n" . " Zeilen %d bis %d\n" . " hat die Modifizierer %d [%s]\n", $class->isInternal() ? 'internal' : 'user-defined', $class->isAbstract() ? ' abstract' : '', $class->isFinal() ? ' final' : '', $class->isInterface() ? 'interface' : 'class', $class->getName(), var_export($class->getParentClass(), 1), $class->getFileName(), $class->getStartLine(), $class->getEndline(), $class->getModifiers(), implode(' ', Reflection::getModifierNames($class->getModifiers())) );
// Dokumentarischen Kommentar ausgeben printf("---> Dokumentation:\n %s\n", var_export($class->getDocComment(), 1));
// Ausgeben, welche Interfaces von der Klasse implementiert werden printf("---> Implementiert:\n %s\n", var_export($class->getInterfaces(), 1));
// Klassenkonstanten ausgeben printf("---> Konstanten: %s\n", var_export($class->getConstants(), 1));
// Klasseneigenschaften ausgeben printf("---> Eigenschaften: %s\n", var_export($class->getProperties(), 1));
// Klassenmethoden ausgeben printf("---> Methoden: %s\n", var_export($class->getMethods(), 1));
// Wenn die Klassen instantiierbar ist, erzeuge eine Instanz if ($class->isInstantiable()) { $counter = $class->newInstance();
echo '---> Ist $counter Instanz? '; echo $class->isInstance($counter) ? 'ja' : 'nein';
echo "\n---> ist new Object() Instanz? "; echo $class->isInstance(new Object()) ? 'ja' : 'nein'; } ?>
|
|
Anmerkung:
Die Methode newInstance() akzeptiert eine variable
Anzahl von Argumenten, welche der Funktion genau wie in
call_user_func() übergeben werden.
Anmerkung:
$class = new ReflectionClass('Foo'); $class->isInstance($arg)
ist äquivalent zu $arg instanceof Foo oder
is_a($arg, 'Foo').
Die Klasse ReflectionObject erlaubt das Zurückentwickeln
von Objekten.
Die ReflectionMethod Klasse erlaubt es,
Klassenmethoden zurückzuentwickeln.
Um einen Blick in eine Methode zu werfen, muss man zuerst eine Instanz der
ReflectionMethod Klasse erzeugen. Man kann dann
jede der oben aufgeführten Methoden dieser Instanz aufrufen.
Beispiel 19-37. Die ReflectionMethod Klasse verwenden
<?php class Counter { private static $c = 0;
/** * Zähler erhöhen * * @final * @static * @access public * @return int */ final public static function increment() { return ++self::$c; } }
// Erzeuge eine Instanz der ReflectionMethod Klasse $method = new ReflectionMethod('Counter', 'increment');
// Grundlegende Informationen ausgeben printf( "===> Die %s%s%s%s%s%s%s Methode '%s' (welche %s ist)\n" . " deklariert in %s\n" . " Zeilen %d bis %d\n" . " hat die Modifizierer %d[%s]\n", $method->isInternal() ? 'interne' : 'benutzerdefinierte', $method->isAbstract() ? ' abstract' : '', $method->isFinal() ? ' final' : '', $method->isPublic() ? ' public' : '', $method->isPrivate() ? ' private' : '', $method->isProtected() ? ' protected' : '', $method->isStatic() ? ' static' : '', $method->getName(), $method->isConstructor() ? 'der Konstruktor' : 'eine normale Methode', $method->getFileName(), $method->getStartLine(), $method->getEndline(), $method->getModifiers(), implode(' ', Reflection::getModifierNames($method->getModifiers())) );
// Dokumentarischen Kommentar ausgeben printf("---> Dokumentation:\n %s\n", var_export($method->getDocComment(), 1));
// Statische Variablen ausgeben, falls welche existieren if ($statics= $method->getStaticVariables()) { printf("---> Statische Variablen: %s\n", var_export($statics, 1)); }
// Die Methode aufrufen printf("---> Aufruf gibt zurück: "); var_dump($method->invoke(NULL)); ?>
|
|
Anmerkung:
Der Versuch, eine private, protected oder abstract Methode aufzurufen,
wird darin enden, dass eine Exception aus der invoke()
Methode geworfen wird.
Anmerkung:
Für statische Methoden sollten Sie, wie man oben sieht, NULL als erstes
Argument von invoke() übergeben. Für nicht statische
Methoden übergeben Sie eine Instanz der Klasse.
Die ReflectionProperty Klasse lässt Sie
Klasseneigenschaften zurückentwickeln.
Anmerkung:
getDocComment() wurde in PHP 5.1.0 hinzugefügt.
Um einen Blick in eine Eigenschaft zu werfen, müssen Sie zuerst eine
Instanz der Klasse ReflectionProperty erzeugen.
Danach können Sie jede der oben angeführten Methoden der Instanz aufrufen.
Beispiel 19-38. Die ReflectionProperty Klasse verwenden
<?php class String { public $laenge = 5; }
// Erzeuge eine Instanz der Klasse ReflectionPropety $prop = new ReflectionProperty('String', 'length');
// Grundlegende Informationen ausgeben printf( "===> Die %s%s%s%s Eigenschaft '%s' (welche %s wurde)\n" . " hat die Modizifierer %s\n", $prop->isPublic() ? ' public' : '', $prop->isPrivate() ? ' private' : '', $prop->isProtected() ? ' protected' : '', $prop->isStatic() ? ' static' : '', $prop->getName(), $prop->isDefault() ? 'zur Kompilierungszeit deklariert' : 'zur Laufzeit erzeugt', var_export(Reflection::getModifierNames($prop->getModifiers()), 1) );
// Eine Instanz von String erzeugen $obj= new String();
// Aktuellen Wert abfragen printf("---> Wert ist: "); var_dump($prop->getValue($obj));
// Wert ändern $prop->setValue($obj, 10); printf("---> Setze Wert auf 10, neuer Wert ist: "); var_dump($prop->getValue($obj));
// Objekt ausgeben var_dump($obj); ?>
|
|
Anmerkung:
Der Versuch, den Wert einer private oder protected Klasseneigenschaft
zu lesen oder zu setzen, wird darin enden, dass eine Exception geworfen
wird.
Die ReflectionExtension Klasse lässt Sie
Extensions zurückentwickeln. Man kann alle geladenen Extensions zur
Laufzeit mittels get_loaded_extensions() abrufen.
Um einen Blick in eine Extension zu werfen, muss man zuerst eine Instanz
der Klasse ReflectionExtension erzeugen. Danach kann
man alle oben aufgeführten Methoden der Instanz aufrufen.
Beispiel 19-39. Die ReflectionExtension Klasse verwenden
<?php // Erzeuge eine neue Instanz der ReflectionExtension Klasse $ext = new ReflectionExtension('standard');
// Grundlegende Informationen ausgeben printf( "Name : %s\n" . "Version : %s\n" . "Funktionen : [%d] %s\n" . "Konstanten : [%d] %s\n" . "INI Einträge : [%d] %s\n" . "Klassen : [%d] %s\n", $ext->getName(), $ext->getVersion() ? $ext->getVersion() : 'NO_VERSION', sizeof($ext->getFunctions()), var_export($ext->getFunctions(), 1),
sizeof($ext->getConstants()), var_export($ext->getConstants(), 1),
sizeof($ext->getINIEntries()), var_export($ext->getINIEntries(), 1),
sizeof($ext->getClassNames()), var_export($ext->getClassNames(), 1) ); ?>
|
|
Für den Fall, dass Sie spezialisierte Versionen der eingebauten Klassen
erzeugen wollen (zum Beispiel, um kolorierte HTML Ausgaben zu erzeugen oder
leicht zugängliche Klassenvariablen oder -methoden oder Hilfmethoden
hinzuzufügen), können Sie fortfahren und die Klassen ableiten.
Beispiel 19-40. Erweiterung der eingebauten Klassen
<?php /** * M_Reflection_Method Klasse */ class My_Reflection_Method extends ReflectionMethod { public $visibility = '';
public function __construct($o, $m) { parent::__construct($o, $m); $this->visibility= Reflection::getModifierNames($this->getModifiers()); } }
/** * Demoklasse #1 * */ class T { protected function x() {} }
/** * Demoklasse #2 * */ class U extends T { function x() {} }
// Informationen ausgeben var_dump(new My_Reflection_Method('U', 'x')); ?>
|
|
Anmerkung:
Achtung: Wenn Sie den Konstruktor überschreiben, denken Sie daran,
den Vaterkonstruktor _vor_ jedem anderen Code den Sie hinzufügen aufzurufen.
Unterlassung wird zu folgendem Ergebnis führen:
Fatal error: Internal error: Failed to retrieve the reflection object