Reflection – Teil 1: ReflectionClass

Was ist Reflection

Eines der coolsten Features in PHP, was leider so gut wie ohne Dokumentation dasteht. Reflection ist eine Möglichkeit, Meta Informationen über so ziemlich alles in PHP herauszubekommen. Welche Interfaces implementiert eine Klasse? Welche Methoden hat sie? Wieviele Parameter hat eine Funktion / Methode, davon wieviele optionale? Was ist der Default-Wert eines Parameters? Dies und einiges mehr ist wohl nur mit der Reflection herauszubekommen.

Arten der Reflection

Oben habe ich mit meinen Fragen bereits die Grundbereiche der Reflection erschlagen. Was ist nun wie reflektierbar?

  • ReflectionClass – Liefert Infos über Klassen
  • ReflectionObject – Im Prinzip wie die ReflectionClass, nur das der Angriffspunkt nicht die ganze Klasse, sondern eine Instanz dieser ist.
  • ReflectionFunction – Liefert Infos über Funktionen
  • ReflectionMethod – Wie ReflectionFunction, nur mit zusätzlichen – methodenspezifischen – Infos wie den Zugriffstyp (private? abstract? final? …)
  • ReflectionParameter – Liefert Infos über Funktions- und Methodenparameter
  • ReflectionProperty – Liefert Infos über Klassen-Attribute (private? static? Default-Wert? …)

Diesen Klassen widme ich mich nun also in der mehrteiligen Reihe. Los gehts direkt in diesem Teil 1 mit der ReflectionClass (ReflectionObject schenke ich mir), sodass dann in Teil 2 ReflectionFunction und ReflectionMethod gemeinsam behandelt werden. Teil 3 wird sich um die ReflectionParameter handeln. Schließen wird die Serie mit Teil 4 und dem ReflectionProperty. Zu erwarten sind jede Menge Code-Beispiele.

ReflectionClass

Starten werde ich mit einer „Grundinfrastruktur“, die ihr euch bitte genau anschaut. Darauf wird dann ein großer Teil der Codebeispiele dieses Teils basieren. Es sieht erstmal viel aus, ist vom Aufbau her aber total simpel. Es ist einfach nur möglichst viel an Sprachkonstrukten verwendet worden.

interface ITest{}

class A implements ITest
{
	//constants
	const A_Const1 = "A_Const1";
	const A_Const2 = "A_Const2";
	
	//properties
	private $A_Private = "A_Private";
    protected $A_Protected = "A_Protected";
    public $A_Public = "A_Public";
	
	//static properties
	private static $A_PrivateStatic = "A_PrivateStatic";
    protected static $A_ProtectedStatic = "A_ProtectedStatic";
    public static $A_PublicStatic = "A_PublicStatic";
	
	//methods
	public function A_PublicMethod(){}
	private function A_PrivateMethod(){}
	protected function A_ProtectedMethod(){}
	
	//static methodes
	public static function A_PublicStaticMethod(){}
	private static function A_PrivateStaticMethod(){}
	protected static function A_ProtectedStaticMethod(){}
}

/**
 * Thats a cool class
 * For sure!
 */
class B extends A
{
	//constants
	const B_Const1 = "B_Const1";
	const B_Const2 = "B_Const2";
	
	//properties
	private $B_Private = "B_Private";
    protected $B_Protected = "B_Protected";
    public $B_Public = "B_Public";
	
	//static properties
	private static $B_PrivateStatic = "B_PrivateStatic";
    protected static $B_ProtectedStatic = "B_ProtectedStatic";
    public static $B_PublicStatic = "B_PublicStatic";
	
	//methods
	public function B_PublicMethod(){}
	private function B_PrivateMethod(){}
	protected function B_ProtectedMethod(){}
	
	//static methodes
	public static function B_PublicStaticMethod(){}
	private static function B_PrivateStaticMethod(){}
	protected static function B_ProtectedStaticMethod(){}
}

Generelle Klasseninformationen

$refclass = new ReflectionClass("B");
print "Class ".$refclass->getName()." is defined from line ".$refclass->getStartLine()." to ".$refclass->getEndLine()." in file ".$refclass->getFileName();
//Class B is defined from line 37 to 62 in file D:\xampp\htdocs\ref1.php

Konstanten

Alle Konstanten inklusive deren Wert der Klasse und aller Überklassen.

$refclass = new ReflectionClass("B");
print_r($refclass->getConstants());
/*
Array
(
    [B_Const1] => B_Const1
    [B_Const2] => B_Const2
    [A_Const1] => A_Const1
    [A_Const2] => A_Const2
)
*/

Attribute

Alle Attribute (statisch und nicht statisch) der Klasse und aller Überklassen. Schön zu sehen, dass die privaten Attribute der Oberklasse hier fehlen.

$refclass = new ReflectionClass("B");
print_r($refclass->getDefaultProperties()); 
/*
Array
(
    [B_PrivateStatic] => B_PrivateStatic
    [B_ProtectedStatic] => B_ProtectedStatic
    [B_PublicStatic] => B_PublicStatic
    [A_ProtectedStatic] => A_ProtectedStatic
    [A_PublicStatic] => A_PublicStatic
    [B_Private] => B_Private
    [B_Protected] => B_Protected
    [B_Public] => B_Public
    [A_Protected] => A_Protected
    [A_Public] => A_Public
)
*/

DocBlock

Der Doc-Block Kommentar der Klasse.

$refclass = new ReflectionClass("B");
print $refclass->getDocComment();
/**
 * Thats a cool class
 * For sure!
 */

Interfaces

Alle Interfaces, die die Klasse (und Oberklassen dieser) implementieren. Als Value wird wieder ein ReflectionClass Objekt übergeben, welches man dann nach gleichem Schema reflecten kann.

$refclass = new ReflectionClass("B");
print_r($refclass->getInterfaces()); 
/*
Array
(
    [ITest] => ReflectionClass Object
        (
            [name] => ITest
        )
)
*/

Methoden

Alle Methoden der Klasse und aller Oberklassen. Hierbei sind merkwürdigerweise (vergleiche den Punkt Attribute) auch die privaten Methoden der Oberklasse dabei. Gilt sowohl für statische wie auch für nicht statische Methoden.

$refclass = new ReflectionClass("B");
print_r($refclass->getMethods());
/*
Array
(
    [0] => ReflectionMethod Object
        (
            [name] => B_PublicMethod
            [class] => B
        )
    [1] => ReflectionMethod Object
        (
            [name] => B_PrivateMethod
            [class] => B
        )
    [2] => ReflectionMethod Object
        (
            [name] => B_ProtectedMethod
            [class] => B
        )
    [3] => ReflectionMethod Object
        (
            [name] => B_PublicStaticMethod
            [class] => B
        )
    [4] => ReflectionMethod Object
        (
            [name] => B_PrivateStaticMethod
            [class] => B
        )
    [5] => ReflectionMethod Object
        (
            [name] => B_ProtectedStaticMethod
            [class] => B
        )
    [6] => ReflectionMethod Object
        (
            [name] => A_PublicMethod
            [class] => A
        )
    [7] => ReflectionMethod Object
        (
            [name] => A_PrivateMethod
            [class] => A
        )
    [8] => ReflectionMethod Object
        (
            [name] => A_ProtectedMethod
            [class] => A
        )
    [9] => ReflectionMethod Object
        (
            [name] => A_PublicStaticMethod
            [class] => A
        )
    [10] => ReflectionMethod Object
        (
            [name] => A_PrivateStaticMethod
            [class] => A
        )
    [11] => ReflectionMethod Object
        (
            [name] => A_ProtectedStaticMethod
            [class] => A
        )
)
*/

Als optionalen Parameter kann man in getMethods() noch spezifizieren, was man genau für Methoden zurück möchte. Zur Auswahl stehen: ReflectionMethod::IS_STATIC, ReflectionMethod::IS_PUBLIC, ReflectionMethod::IS_PROTECTED, ReflectionMethod::IS_PRIVATE, ReflectionMethod::IS_ABSTRACT, ReflectionMethod::IS_FINAL und auch Kombinationen davon. Beispiel:

$refclass = new ReflectionClass("B");
print_r($refclass->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PRIVATE));

Würde zum Beispiel alle statischen und alle privaten Methoden zurückgeben.

Static Properties

Alle statischen Attribute der Klasse selbst und ihrer Oberklassen. Hierbei ist wieder zu bemerken, dass die privaten statischen Attribute der Oberklasse fehlen.

$refclass = new ReflectionClass("B");
print_r($refclass->getStaticProperties());
/*
Array
(
    [B_PrivateStatic] => B_PrivateStatic
    [B_ProtectedStatic] => B_ProtectedStatic
    [B_PublicStatic] => B_PublicStatic
    [A_ProtectedStatic] => A_ProtectedStatic
    [A_PublicStatic] => A_PublicStatic
)
*/

Prüfung auf Abstraktheit einer Klasse

$refclass = new ReflectionClass("B");
var_dump($refclass->isAbstract());
//bool(false)

Prüfung auf Klassentyp

Okay, keine wirklich tolle Überschrift. Prinzip ist aber einfach. Es geht darum zu prüfen, ob die reflektierte Klasse selbst geschrieben wurde oder „PHP-intern“ ist. Das Beispiel machts klar:

$refclass = new ReflectionClass("StdClass");
var_dump($refclass->isUserDefined());
//bool(false)

$refclass = new ReflectionClass("A");
var_dump($refclass->isUserDefined());
//bool(true)

To be continued

Das wars also mit der ReflectionClass. Ein paar Methoden habe ich unterschlagen, um es nicht unnötig aufzublähen. Für alles weitere steht das PHP Handbuch zur ReflectionClass gern zur Verfügung. Im nächsten Teil gehts weiter mit ReflectionFunction und ReflectionMethod.

Folgende Teile:

Weitere Posts:

Dieser Beitrag wurde unter php, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

3 Antworten auf Reflection – Teil 1: ReflectionClass

  1. Pingback: Reflection – Teil 2: ReflectionMethod und ReflectionFunction | davblog – webdev and stuff

  2. Pingback: Reflection – Teil 3: ReflectionParameter | davblog – webdev and stuff

  3. Pingback: Reflection – Teil 4: ReflectionProperty | davblog – webdev and stuff

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.