php.de

Zurück   php.de > php.de Intern > Beitragsarchiv > Adventskalender 2008

 
 
LinkBack Themen-Optionen
Alt 22.12.2008, 00:00  
Adventskalenderöffner
 
Benutzerbild von Nikolaus 2.0
 
Registriert seit: 27.11.2008
Beiträge: 72
PHP-Kenntnisse:
Fortgeschritten
Nikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nettNikolaus 2.0 ist einfach richtig nett
Standard 10110: Spieglein, Spieglein an der Wand…

10110:
Unter Reflexion oder auch Introspektion versteht man in der Programmierung die Möglichkeit, dass ein Programm zur Laufzeit die eigene Struktur untersuchen und gegebenenfalls auch modifizieren kann. Reflexion wird von den meisten Programmiersprachen, die Objektorientierung bieten, unterstützt, so auch von PHP. Zunächst stellt sich aber die Frage, wozu man Reflexion überhaupt benötigt. Nun ja, es gibt mehrere Gründe. Der eine ist, dass das Programm stark modular gehalten ist und deshalb einzelne Strukturteile variieren können. Ein sehr einfaches Beispiel von Reflexion hat sicherlich jeder schon einmal angewendet:
PHP-Code:
if (class_exists('MyClass')) {
    print 
'Klasse existiert';

Ein anderes Beispiel, bei dem es mehr um den Inhalt eines Objekts denn um dessen Vorhandensein geht, ist dieses:
PHP-Code:
$vars get_object_vars($myObject); 
Ich denke, nun ist etwas klarer, worum es bei Introspektion geht.

PHP bietet aber seit der Version 5.0.0 mit Einführung der Reflection-API eine weitaus mächtigere Möglichkeit, einzelne Klassen, Objekte oder Funktionen zu analysieren.
Um diese Möglichkeiten zu demonstrieren, erstellen wir ersteinmal eine simple Klasse. Hier wurde ein stupides nutzloses Singleton gewählt, da man dort gleich auf Anhieb schön viele Methoden und auch eine Eigenschaft verwenden kann. Das Ganze ist natürlich auch pflichtbewusst dokumentiert.
PHP-Code:
<?php
/**
 * Just a simple test class
*/
class TestClass
{
    
/**
     * Contains the instance.
     * 
     * @var TestClass
    */
    
private static $__instance null;
    
    
    
/**
     * Returns the instance. Use this method instead of the constructor!
     * 
     * @return TestClass
    */
    
public static function getInstance()
    {
        if (
null === self::$__instance) {
            
self::$__instance = new self;
        }
        
        return 
self::$__instance;
    }
    
    
    
/**
     * Protect access to constructor.
    */
    
protected function __construct()
    {
    }
    
    
    
/**
     * Disallow cloning.
    */
    
private function __clone()
    {
    }
    
    
    
/**
     * Return a random number.
     * Chosen by fair dice roll, guaranteed to be random.
     * Inspired by xkcd <http://xkcd.com/221/> :-)
     * 
     * @return integer
    */
    
public function getRandomNumber()
    {
        return 
4;
    }
}
Jetzt soll die Klasse analysiert werden. Um dies zu tun, wird die Klasse ReflectionClass herangezogen. Von dieser wird eine neue Instanz abgeleitet, wobei dem Konstruktor der Name der zu untersuchenden Klasse übergeben wird:
PHP-Code:
$testClassRefl = new ReflectionClass('TestClass'); 
Soweit so schön. Um nun die Informationen über die reflektierte Klasse zu erhalten, muss man nicht viel herumprogrammieren, weil die Klasse die Methode __toString() implementiert und so ein simples echo oder print seinen Dienst tut:
PHP-Code:
print '<pre>' $testClassRefl '</pre>'
Die Methode __toString() greift übrigens auf die statische Methode export() zu, weshalb man das auch anders machen kann:
PHP-Code:
print '<pre>' ReflectionClass::export(TestClass::getInstance(), true) . '</pre>'
Doch das nur so am Rande…

Das Ergebnis ist schonmal recht üppig:
Code:
/**
 * Just a simple test class
*/
Class [  class TestClass ] {
  @@ C:\Programme\xampp\htdocs\test.php 5-57

  - Constants [0] {
  }

  - Static properties [1] {
    Property [ private static $__instance ]
  }

  - Static methods [1] {
    /**
     * Returns the instance. Use this method instead of the constructor!
     * 
     * @return TestClass
    */
    Method [  static public method getInstance ] {
      @@ C:\Programme\xampp\htdocs\test.php 20 - 27
    }
  }

  - Properties [0] {
  }

  - Methods [3] {
    /**
     * Protect access to constructor.
    */
    Method [  protected method __construct ] {
      @@ C:\Programme\xampp\htdocs\test.php 33 - 35
    }

    /**
     * Disallow cloning.
    */
    Method [  private method __clone ] {
      @@ C:\Programme\xampp\htdocs\test.php 41 - 43
    }

    /**
     * Return a random number.
     * Chosen by fair dice roll, guaranteed to be random.
     * Inspired by xkcd <http://xkcd.com/221/> :-)
     * 
     * @return integer
    */
    Method [  public method getRandomNumber ] {
      @@ C:\Programme\xampp\htdocs\test.php 53 - 56
    }
  }
}
Man sieht: die gesamte Struktur der Klasse wurde in einem Pseudocode wiedergegeben und sogar die DocBlocks wurden (zumindest bei der Klasse selbst und den Methoden) beachtet. So lassen sich z.B. auch Dokumentationen generieren.
Diese Ausgabe ist jedoch etwas unpraktisch und dient mehr der Übersicht oder zu Debugging-Zwecken. Die Analyse lässt sich auch etwas verfeinern, indem man nur einzelne Elemente betrachtet. Hierfür bietet die Klasse ReflectionClass viele, viele weitere Methoden, von denen eine kleine Auswahl hier vorgestellt wird:
PHP-Code:
$testClassRefl = new ReflectionClass('TestClass');
print 
'Name: '          $testClassRefl->getName()       . '<br>';
print 
'File: '          $testClassRefl->getFileName()   . '<br>';
print 
'Lines: '         $testClassRefl->getStartLine()  . ' unto ' $testClassRefl->getEndLine() . '<br>';
print 
'DocBlock: <pre>' $testClassRefl->getDocComment() . '</pre>'
Das Ergebnis:
Code:
Name: TestClass
File: C:\Programme\xampp\htdocs\test.php
Lines: 5 unto 57
DocBlock: 
/**
 * Just a simple test class
*/
Damit ist schonmal die Struktur der Klasse selbst erfragt. Kommen wir zu den Methoden. Um Methoden zu erfragen, existiert die Methode getMethods(), welche ein Array mit Objekten für die einzelnen Methoden zurückgibt.
PHP-Code:
$testClassRefl = new ReflectionClass('TestClass');
print 
'<pre>' print_r($testClassRefl->getMethods(), true) . '</pre>'
Code:
Array
(
    [0] => ReflectionMethod Object
        (
            [name] => getInstance
            [class] => TestClass
        )

    [1] => ReflectionMethod Object
        (
            [name] => __construct
            [class] => TestClass
        )

    [2] => ReflectionMethod Object
        (
            [name] => __clone
            [class] => TestClass
        )

    [3] => ReflectionMethod Object
        (
            [name] => getRandomNumber
            [class] => TestClass
        )

)
Das Ergebnis zeigt, dass jede Methode vom Typ ReflectionMethod ist. Diese Klasse bietet ähnliche Methoden wie die Klasse ReflectionClass, die wir schon behandelt haben.
Nicht immer will man aber alle Methoden abfragen, weshalb es auch möglich ist, eine bestimmte Methode direkt anzusprechen:
PHP-Code:
$testClassRefl = new ReflectionClass('TestClass');
print 
'<pre>' $testClassRefl->getMethod('getRandomNumber') . '</pre>'
Das Ergebnis ist dem ersten Ergebnis recht ähnlich:
Code:
/**
     * Return a random number.
     * Chosen by fair dice roll, guaranteed to be random.
     * Inspired by xkcd <http://xkcd.com/221/> :-)
     * 
     * @return integer
    */
Method [  public method getRandomNumber ] {
  @@ C:\Programme\xampp\htdocs\test.php 53 - 56
}
Es ist jedoch nicht nur möglich, Methoden zu analysieren, man kann sie sogar ausführen und auch ihr Ergebnis verwerten. Da Methoden jedoch in aller Regel im Kontext eines Objekts aufgerufen werden, muss zunächst eine Instanz der zu analysierenden Klasse erstellt werden. Um Methoden dann schließlich auszuführen, kann die Methode invoke() benutzt werden, die eine variable Anzahl an Parametern erlaubt. Der erste ist dabei Pflicht und fordert das Objekt der Klasse, die restlichen sind optional und sind die Parameter, die an die auszuführende Methode übergeben werden. In unserem Falle haben wir aber keine Parameter.
PHP-Code:
$testObj TestClass::getInstance();
$testClassRefl = new ReflectionClass('TestClass');
print 
$testClassRefl->getMethod('getRandomNumber')->invoke($testObj); 
Das Ergebnis ist (wie zu erwarten war) 4.
Analog zu getMethods()/getMethod() existieren natürlich auch getProperties()/getProperty(). Da diese jedoch sehr ähnlich funktionieren, wird an dieser Stelle nicht näher darauf eingegangen.

Neben der ReflectionClass gibt es auch noch eine Reihe anderer Klassen, von denen ich mir jetzt aber nur eine heraussuche und zwar ReflectionObject. Diese dient dazu, ein Objekt zu inspizieren und sorgt dabei gerne für Verwirrung. Der Name kann nämlich leicht in die Irre führen, da hierbei nicht wirklich das Objekt selbst, sondern die Klasse dieses Objekts untersucht wird. Dies kann man auch leicht daran sehen, dass ReflectionObject eine Kindklasse von ReflectionClass ist. Der größte Unterschied besteht lediglich darin, dass dem Konstruktor nicht der Name der Klasse sondern ein Objekt übergeben wird:
PHP-Code:
$testObj TestClass::getInstance();
$testObjRefl = new ReflectionObject($testObj);
print 
'<pre>' $testObjRefl '</pre>'
Das Ergebnis ist fast identisch, lediglich die Beschriftung der Klasse hat sich geändert. Außerdem ist die Sektion Dynamic properties hinzugekommen, welche Eigenschaften beinhaltet, die erst zur Laufzeit hinzugefügt wurden.
Es geht hier also wirklich nur um die Struktur; für eine Analyse des Status eines Objekts zur Laufzeit muss daher auf get_object_vars() zurückgegriffen werden.
Code:
/**
 * Just a simple test class
*/
Object of class [  class TestClass ] {
  @@ C:\Programme\xampp\htdocs\test.php 5-57

  - Constants [0] {
  }

  - Static properties [1] {
    Property [ private static $__instance ]
  }

  - Static methods [1] {
    /**
     * Returns the instance. Use this method instead of the constructor!
     * 
     * @return TestClass
    */
    Method [  static public method getInstance ] {
      @@ C:\Programme\xampp\htdocs\test.php 20 - 27
    }
  }

  - Properties [0] {
  }

  - Dynamic properties [0] {
  }

  - Methods [3] {
    /**
     * Protect access to constructor.
    */
    Method [  protected method __construct ] {
      @@ C:\Programme\xampp\htdocs\test.php 33 - 35
    }

    /**
     * Disallow cloning.
    */
    Method [  private method __clone ] {
      @@ C:\Programme\xampp\htdocs\test.php 41 - 43
    }

    /**
     * Return a random number.
     * Chosen by fair dice roll, guaranteed to be random.
     * Inspired by xkcd  :-)
     * 
     * @return integer
    */
    Method [  public method getRandomNumber ] {
      @@ C:\Programme\xampp\htdocs\test.php 53 - 56
    }
  }
}
Die Klasse selbst funktioniert sonst aber genauso wie ReflectionClass auch und bedarf deshalb keiner genaueren Beschreibung.

Ihr merkt: Reflexion ist ein umfangreiches Thema, sogar so umfangreich, dass hier nur ein kleiner Einblick gegeben werden kann, doch ist meist gerade dieser Einblick besonders wichtig, da Die Reflection-API zu Anfang oft ein wenig schwer zu verstehen ist und das PHP-Manual die Verwirrung meist nur noch größer macht. Hat man jedoch einmal einen Einblick bekommen, sollte der Rest klar sein. Deshalb hier auch der Link zu offiziellen Dokumentation:
Nikolaus 2.0 ist offline  
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 22.12.2008, 01:34  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.248
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Schön. Hatten wir MODs auch noch ne kleine Überraschung. Danke.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline  
Alt 22.12.2008, 16:16  
Erfahrener Benutzer
 
Registriert seit: 16.07.2005
Beiträge: 1.007
PHP-Kenntnisse:
Fortgeschritten
brian johnson befindet sich auf einem aufstrebenden Ast
Standard

interessant ist auch ReflectionExtension>
PHP-Code:
// Create an instance of the ReflectionExtension class
$ext = new ReflectionExtension('standard');

// Print out basic information
printf(
    
"Name        : %s\n" .
    
"Version     : %s\n" .
    
"Functions   : [%d] %s\n" .
    
"Constants   : [%d] %s\n" .
    
"INI entries : [%d] %s\n" .
    
"Classes     : [%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)
); 
__________________
PHP4?!?>>>Aktuelle PHP Version: 5.2.11 || 5.3.0
Suse 11.2 *vorfreude*
brian johnson ist offline  
 


Themen-Optionen

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php reflectionclass, reflectionclass php, reflection class php, php $__instance, php was macht reflectionclass, reflectionclass php version, spieglein spieglein an der wand, php reflection protected constructor, refectionclass php, php was ist eine reflectionclass, php \new reflectionclass\, reflectionclass welche version php, php how to use reflectionclass, chosen by fair dice, php getdoccomment, introspektion in die reflectionclass und php, php reflection private constructor -java, spieglein spieglein an der wand nuber, .reflectionclass.php, php \reflectionclass\

Alle Zeitangaben in WEZ +1. Es ist jetzt 16:44 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum