Back To Top

PHP und die Reflection API

Reflection API von PHP5

Comelio-Blog PHP ReflectionDie neuen Möglichkeiten, in PHP objektorientiert zu arbeiten, haben die Sprache einen großen Schritt nach vorne gebracht. Allerdings ist es keine rein objektorientierte Sprache, sondern weiterhin eine Skriptsprache, sodass man im Regelfall einen gemischten Quelltext enthält, in dem bisweilen Objekte genauso aufgerufen werden wie kleine Bereiche prozedural nach Seitenerfordernis programmiert werden. Dieses Kapitel dreht sich um die OOP-Möglichkeiten von PHP und verwendet einen Großteil der Funktionen, die bereits in PHP4 vorhanden waren, sehr viele neue Funktionen und Klassen und versucht auch, Techniken der Objektorientierung, die nun erst in PHP5 umsetzbar sind, auch tatsächlich umzusetzen.

In diesem Artikel werden die neuen Klassen für Reflection in mehreren Beispielen verwendet. Sie sind tatsächlich ganz neu in PHP5 eingeführt worden und ähneln entsprechenden Konstrukten anderer Programmiersprachen. Sie ermöglichen umfangreiche Analysen von vorhandenen Klassen, ihren Methoden, Eigenschaften und Erweiterungen von PHP. Die Syntax ist nicht zu einfach zu verwenden wie die vorangegangen Funktionen für die Untersuchung von Funktionen, Klassen und Variablen, doch bieten sie größere Informationsmengen und sind besser erstellt, was sich insbesondere auf die Benennungsregeln auswirkt. Auch diese Klassen sind weniger für den täglichen Programmeinsatz bestimmt, sondern eher für die Untersuchung von vorhandenen Klassen bei der Programmentwicklung. Die neuen Klassen heißen:

  • class Reflection { }
  • interface Reflector { }
  • class Reflection_Exception extends Exception { }
  • class Reflection_Function implements Reflector { }
  • class Reflection_Parameter implements Reflector { }
  • class Reflection_Method extends Reflection_Function { }
  • class Reflection_Class implements Reflector { }
  • class Reflection_Property implements Reflector { }
  • class Reflection_Extension implements Reflector { }

Insbesondere die neu eingeführten Reflection-Klassen, allerdings auch die Funktionsfunktionen, bieten Möglichkeiten, Programmen über Zeichenketten und nicht über ihre Bezeichner aufzurufen. Es bestehen damit Möglichkeiten, erst eine Klasse zu untersuchen, um dann mit entsprechenden Methoden ein Objekt zu instanziieren oder sogar eine Methode aufzurufen bzw. Eigenschaften Werte zuzuweisen. Dies öffnet den Weg, nach einer allgemeinen Untersuchung mit den gefundenen Werten auch sofort einen Test durchzuführen. Für Funktionen gab es so etwas bereits in Ansätzen über auch in PHP4 vorhandene Funktionen. Hier lassen sich auch über eine spezielle Funktion neue Funktionen in Kurzschreibweisen wie z.B. für den Einsatz in einigen Array-Funktionen erzeugen.

Bei sehr großen Anwendungen bieten sich über diese zusätzlichen (allerdings nur in Zend zur Verfügung stehenden) Spracheigenschaften u.a. Gelegenheiten, umfangreiche und strukturierte Tests für fertige Klassen zu entwickeln, da in stets gleichen (eigenen) Programmen vorhandene Klassen sowie ihre Inhalte auf grundsätzliche Funktionstüchtigkeit getestet werden können.

In diesem Artikel befinden sich daher sowohl Beispiele, mit denen ganz einfach vorhandene Variablen, Funktionen und Klassen ausgegeben und allgemein auf ihren grundlegenden Eigenarten untersucht werden. Allerdings gibt es auch eine Reihe von Beispielen, die mit den neuen Reflection-Klassen tiefer in Klassen einsteigen und gezielt ihre Eigenarten untersuchen und versuchen, soweit es die in den verwendeten Klassen vorhandenen Methoden erlauben, viele Merkmale auszugeben. Einen dritten großen Bereich bieten dann Rezepte, welche Funktionen und Klassen aufrufen und allgemein testen, um dann Informationen zu den zurückgelieferten Werten bzw. Objekten zu liefern. Diese Informationen können naturgemäß nur sehr allgemein sein, da man für umfangreiche Tests natürlich insbesondere Wert auf individuelle Rückgabedatenstrukturen oder Gegebenheiten legt, die allgemein so nicht vorherzusehen sind. Doch für einen schnellen Überblick über das z.B. auch von Kollegen erstellte Material eignen sie sich in jedem Fall – und wie immer steht niemand einer benötigten Individualisierung und Erweiterung im Wege.

Reflection: Wie erhalte ich Klasseninformationen?

Comelio-Blog PHP ReflectionAllgemeine Klasseninformationen lassen sich über wenige Quelltextzeilen direkt mit Hilfe der Reflection-API auslesen. Die anderen Beispiele stellen im Gegensatz zu diesem Beispiel umfangreichere Varianten bzw. detaillierte Auflistungen von Informationen dar, die von dieser Methode ebenfalls in Grundzügen geliefert werden. Neben dem einfachen Objekt- und Methodenaufruf testet die Methode zusätzlich darauf, ob die übergebene Klasse zurzeit überhaupt existiert.

class Class_Reflector {
 // Properties
 var $Class;
 var $Function;

 // Output of general information
 function Reflect_Class(){
   if (class_exists($this->Class)){
     $Reflector = new Reflection_Class($this->Class);
     return $Reflector->export($this->Class);
   }
   else {
     return false;
   }
 }
}

reflection.php

Für den Test der Methode benötigt man die eingebundene Klasse Class_Reflector sowie ein Objekt dieser Klasse. Die Ausgabe der Datenstruktur erfolgt nicht über eine eigene foreach-Schleife, sondern ganz einfach über die print_r()-Funktion, damit die Datenstruktur, welche von der Methode zurückgeliefert wird, besonders deutlich wird. Wichtig für diesen Test ist insbesondere die Einbindung einer eigenen Testklasse wie sie bereits im Skript Reflection: Wie erhalte ich Klasseninformationen? verwendet wurde.

// Inclusion of classes
include("test_class.php");
include("class_reflector.php");

$Reflector = new Class_Reflector();
$Reflector ->Class = "Friend";

// Use reflection-class
echo "<pre>";
print_r($Reflector->Reflect_Class());
echo "</pre>";

class_reflector_test.php

Man erhält einen überaus umfangreich formatierten Bericht, in dem auch solche Angaben wie der Dateiname und die Zeilenzahl stehen, zwischen denen die Klasse erstellt wird. Diese Angaben zählen zu denen, die in anderen Beispielen (Reflection: Wie untersuche ich Klassen? oder Reflection: Wie untersuche ich Methoden?) mit speziellen Methoden ausfindig gemacht werden. Zwar ist die Verwendung der gerade vorgestellten Methode wesentlich schneller, doch kann man die Formatierung des Berichts nicht beeinflussen.

Class [   class friend extends person ] {
  @@ C:\Programme\Apache Group\Apache2\htdocs
       \PHPCodebook\1_OOP\test_class.php 28-71

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [5] {
    Property [  public $Nickname ]
    Property [  public $Profession ]
…
  }

  - Methods [5] {
    Method [   public method __construct ] {
      @@ C:\Programme\Apache Group\Apache2\htdocs\PHPCodebook
           \1_OOP\test_class.php 35 - 39

      - Parameters [3] {
        Parameter #0 [ $Given_Name ]
        Parameter #1 [ $Family_Name ]
        Parameter #2 [ $Nickname ]
      }
    }

    Method [  public method Say_Hello ] {
      @@ C:\Programme\Apache Group\Apache2\htdocs\PHPCodebook
           \1_OOP\test_class.php 41 - 48
    }

…
  }
}

Ausgabe im Browser

Reflection: Wie untersuche ich Klassen?

Comelio-Blog PHP ReflectionDie neue Klasse Reflection_Class bietet Möglichkeiten, Klasseneigenarten zu untersuchen und enthält die folgenden Methoden. Sie erfassen solche Informationen wie den Namen, die zugehörigen Methoden, ihren Typ und ihre Vererbungsstrukturen.

  class Reflection_Class implements Reflector {
      public __construct(string name)
      public string getName()
      public bool isInternal()
      public bool isUserDefined()
      public string getFileName()
      public int getStartLine()
      public int getEndLine()
      public string getDocComment()
      public Reflection_Method getConstructor()
      public Reflection_Method getMethod(string name)
      public Reflection_Method[] getMethods()
      public Reflection_Property getProperty(string name)
      public Reflection_Property[] getProperties()
      public array getConstants()
      public mixed getConstant(string name)
      public bool isInstantiable()
      public bool isInterface()
      public bool isFinal()
      public bool isAbstract()
      public int getModifiers()
      public bool isInstance(stdclass object)
      public stdclass newInstance(mixed* args)
      public Reflection_Class[] getInterfaces()
      public Reflection_Class getParentClass()
      public string toString()
      public bool isSubclassOf(Reflection_Class class)
  }

Struktur der Reflection_Class-Klasse

Mit der folgenden Methode der Klasse Class_Reflector erhält man Informationen über eine vorhandene Klasse in Form eines assoziativen Arrays, in dem die durch die Reflection-API verfügbaren Informationen eingelesen werden. Dieses Beispiel ähnelt dem Rezept Reflection: Wie erhalte ich Klasseninformationen?, ist allerdings wesentlich ausführlicher. Es lässt sich kombiniert einsetzen mit dem Beispiel Reflection: Wie untersuche ich Methoden?.

// Documentation of classes
 function Doc_Class(){
   if (class_exists($this->Class)){
     // Initialize object
     $Class = new Reflection_Class($this->Class);
     // Prepare output data
     $Text = array();
     // Collect information
     // Is class internal or user-defined?
     $Text["internal"] =
   $Class->isInternal() ? 'internal' : 'user-defined';
     // Is class abstract?
     $Text["abstract"] =
   $Class->isAbstract() ? ' abstract' : 'notAbstract';
     // Is class final?
     $Text["final"] =
            $Class->isFinal() ? ' final' : 'notFinal';
     // Is class an interface?
     $Text["isInterface"] =
    $Class->isInterface() ? 'isInterface' : 'isClass';
     // Class name
     $Text["name"] = $Class->getName();
     // Parent class
     $Text["parent"] =
              var_export($Class->getParentClass(), 1);
     // File name
     $Text["file"] = $Class->getFileName();
     // Start line in file
     $Text["startLine"] = $Class->getStartLine();
     // End line in file
     $Text["endLine"] = $Class->getEndline();
     // Class modifiers
     $Text["modifiers"] = $Class->getModifiers();
      //implode(' ', Reflection::getModifierNames($class->getModifiers()))
      // Documentation
     $Text["doc"] = var_export($Class->getDocComment(), 1);
     // Interfaces
     $Text["interfaces"] =
               var_export($Class->getInterfaces(), 1);
     // Class constants
     $Text["constants"] =
                var_export($Class->getConstants(), 1);
     // Class properties
     $Text["properties"] =
               var_export($Class->getProperties(), 1);
     // Class methods
     $Text["methods"] =
                  var_export($Class->getMethods(), 1);
     // Is class instantiable?
     $Text["instantiable"] = $Class->isInstantiable() ? 'instantiable' : 
                                                        'notInstantiable';
     // Return value
     return $Text;
   }
   else {
     return false;
   }
 }

class_reflector.php

Für den Test der Methode benötigt man die eingebundene Klasse Class_Reflector sowie ein Objekt dieser Klasse. Die Ausgabe der Datenstruktur erfolgt nicht über eine eigene foreach-Schleife, sondern ganz einfach über die print_r()-Funktion, damit die Datenstruktur, welche von der Methode zurückgeliefert wird, besonders deutlich wird. Wichtig für diesen Test ist insbesondere die Einbindung einer eigenen Schnittstelle und einer eigenen Klasse.

include("test_interface.php");
$Reflector = new Class_Reflector();
$Reflector ->Class = "Citizen";
// Use reflection-class
echo "<pre>";
print_r($Reflector->Doc_Class());
echo "</pre>";

class_reflector_test.php

Man erhält ein umfangreiches Array in assoziativer Form mit Informationen zu den Eigenarten der untersuchten Klasse.

Array
(
    [internal] => user-defined
    [abstract] => notAbstract
    [final] => notFinal
    [isInterface] => isClass
    [name] => Citizen
    [parent] => false
    [file] => C:\Programme\Apache Group\Apache2\htdocs\PHPCodebook
                \1_OOP\test_interface.php
    [startLine] => 10
    [endLine] => 32
    [modifiers] => 0
    [doc] => false
    [interfaces] => array (
  0 => 
  class reflection_class {
    var $name = 'person_int';
  },
)
    [constants] => array (
)
    [properties] => array (
  0 => 
  class reflection_property {
    var $name = 'Given_Name';
    var $class = 'citizen';
  },
  1 => 
…
)
    [methods] => array (
  0 => 
  class reflection_method {
    var $name = '__construct';
    var $class = 'citizen';
  },
…
)
    [instantiable] => instantiable
)

Ausgabe im Browser

Reflection: Wie untersuche ich Methoden?

Comelio-Blog PHP ReflectionDie neue Klasse Reflection_Method bietet Möglichkeiten, Informationen über Methoden zu erfahren und enthält folgende Methoden. Sie erfassen den Methodentyp, den Namen, Informationen für Dokumentationszwecke sowie Inhalte der Methode.

  class Reflection_Method extends Reflection_Function {
      public __construct(mixed class, string name)
      public mixed invoke(stdclass object, mixed* args)
      public bool isFinal()
      public bool isAbstract()
      public bool isPublic()
      public bool isPrivate()
      public bool isProtected()
      public bool isStatic()
      public bool isConstructor()
      public int getModifiers()
      public Reflection_Class getDeclaringClass()

      /* Inherited from Reflection_Function */
      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 string toString()
      public bool returnsReference()
      public Reflection_Parameter[] getParameters()
  }

Struktur der Klasse Reflection_Method

Mit der folgenden Methode der Klasse Class_Reflector erhält man Informationen über vorhandene Methoden in Form eines assoziativen Arrays, in dem die durch die Reflection-API verfügbaren Informationen eingelesen werden.

// Documentation of methods
 function Doc_Method(){
   if (class_exists($this->Class)
        && in_array($this->Method,
                   get_class_methods($this->Class))){
    // Initialize object
    $Method= new Reflection_Method($this->Class,
                                   $this->Method);
     // Prepare output data
     $Text = array();
     // Collect information
     // Is method internal or user-defined?
     $Text["internal"] = $Method->isInternal()
                        ? 'internal' : 'user-defined';
     // Is method abstract?
     $Text["abstract"] = $Method->isAbstract()
                        ? ' abstract' : 'notAbstract';
     // Is method final?
     $Text["final"] =  $Method->isFinal()
                              ? ' final' : 'notFinal';
     // Is method public?
     $Text["public"] = $Method->isPublic()
                            ? ' public' : 'notPublic';
     // Is method private?
     $Text["private"] = $Method->isPrivate()
                          ? ' private' : 'notPrivate';
     // Is method protected?
     $Text["protected"] = $Method->isProtected()
                      ? ' protected' : 'notProtected';
     // Is method static?
     $Text["static"] = $Method->isStatic()
                            ? ' static' : 'notStatic';
     // Method name
     $Text["name"] = $Method->getName();
     // Is method the constructor?
     $Text["constructor"] = $Method->isConstructor()
                    ? 'constructor' : 'regularMethod';
     // Class resp. method file
     $Text["file"] = $Method->getFileName();
     // Start line of method declaration
     $Text["startLine"] = $Method->getStartLine();
     // End line of method declaration
     $Text["endLine"] = $Method->getEndline();
     // Modifiers
     $Text["modifiers"] = $Method->getModifiers();
    // Print documentation comment
    $Text["doc"] = var_export(
                         $Method->getDocComment(), 1);
    // Static variables?
    if ($Statics= $Method->getStaticVariables()){
      $Text["statics"] =  var_export($Statics, 1);
    }
    // Return value
    return $Text;
   }
   else{
     return false;
   }
 }

class_reflector.php

Für den Test der Methode benötigt man die eingebundene Klasse Class_Reflector sowie ein Objekt dieser Klasse. Die Ausgabe der Datenstruktur erfolgt nicht über eine eigene foreach-Schleife, sondern ganz einfach über die print_r()-Funktion, damit die Datenstruktur, welche von der Methode zurückgeliefert wird, besonders deutlich wird. Wichtig für diesen Test ist insbesondere die Einbindung einer eigenen Schnittstelle und einer eigenen Test-Klasse. Als Übergabeparameter benutzt man den Klassennamen und einen Methodennamen.

$Reflector ->Class = "Citizen";
$Reflector->Method = "__construct";

// Use reflection-class
echo "<pre>";
print_r($Reflector->Doc_Method());
echo "</pre>";

class_reflector_test.php

Man erhält ein umfangreiches assoziatives Array mit Informationen zur untersuchten Methode.

Array
(
    [internal] => user-defined
    [abstract] => notAbstract
    [final] => notFinal
    [public] =>  public
    [private] => notPrivate
    [protected] => notProtected
    [static] => notStatic
    [name] => __construct
    [constructor] => constructor
    [file] => C:\Programme\Apache Group\Apache2\htdocs\PHPCodebook
                \1_OOP\test_interface.php
    [startLine] => 16
    [endLine] => 19
    [modifiers] => 8448
    [doc] => false
)

Ausgabe im Browser

Reflection: Wie untersuche ich Eigenschaften?

Comelio-Blog PHP ReflectionDie neue Klasse Reflection_Property enthält die folgenden Methoden, mit denen sich Informationen zu einer übergebenen Klasseneigenschaft ermitteln lassen.

  class Reflection_Property implements Reflector {
      public __construct(mixed class, string name)
      public string getName()
      public bool isPublic()
      public bool isPrivate()
      public bool isProtected()
      public bool isStatic()
      public bool isDefault()
      public int getModifiers()
      public mixed getValue(stdclass object)
      public void setValue(stdclass object, mixed value)
      public Reflection_Class getDeclaringClass()
      public string toString()
  }

Struktur der Klasse Reflection_Property

Mit der folgenden Methode der Klasse Class_Reflector erhält man Informationen über eine vorhandene Eigenschaft in Form eines assoziativen Arrays, in dem die durch die Reflection-API verfügbaren Informationen eingelesen werden.

function Doc_Property(){
   if (class_exists($this->Class)
       || in_array($this->Property,
                   get_class_vars($this->Class))){
     // Initialize object
     $Property= new Reflection_Property
                      ($this->Class, $this->Property);
     // Prepare output data
     $Text = array();
     // Collect information
     // Is method internal or user-defined?
     // Is property public?
     $Text["public"] = $Property->isPublic()
                            ? ' public' : 'notPublic';
     // Is property private?
     $Text["private"] = $Property->isPrivate()
                          ? ' private' : 'notPrivate';
     // Is property protected?
     $Text["protected"] = $Property->isProtected()
                      ? ' protected' : 'notProtected';
     // Is property static?
     $Text["static"] = $Property->isStatic()
                            ? ' static' : 'notStatic';
     // Property name
     $Text["name"] = $Property->getName();
     // Has property default value?
     $Text["default"] = $Property->isDefault()
                        ? 'compile-time' : 'run-time';
      // Return value
      return $Text;
   }
   else {
     return false;
   }
 }

class_reflector.php

Diese Klasse lässt sich dann mit folgendem Skript testen.

// Test class
class Ship{
  public $length;
  public $width;
}

// Set values
$Reflector->Class = "Ship";
$Reflector->Property = "length";

// Use reflection-class
echo "<pre>";
print_r($Reflector->Doc_Property());
echo "</pre>";

class_reflector_test.php

Man erhält ein umfangreiches assoziatives Array mit Informationen zur untersuchten Eigenschaft.

Array
(
    [public] =>  public
    [private] => notPrivate
    [protected] => notProtected
    [static] => notStatic
    [name] => length
    [default] => compile-time
)

» Kontaktformular










comelio.com

mail address

mail address

  • Berlin | Comelio GmbH
    Fon: +49(0)30-8145622-00
    Fax: +49(0)30-8145622-10
  • München | Comelio GmbH
    Fon: +49(0)89-38156860-0
    Fax: +49(0)89-38156860-9
  • Hamburg | Comelio GmbH
    Fon: +49(0)40-20934996-0
    Fax: +49(0)40-20934996-9
  • Wien | Comelio GmbH
    Fon: +43-720-2097-97
    Fax: +43-720-2097-98