1. Prüfen mit instanceof
In einigen Fällen ist es notwendig, im Verlauf eines Skripts genauer zu bestimmen, ob sich ein Objekt von einer bestimmten Klasse ableitet oder ein ebenso bestimmtes Interface implementiert. Dieser Test wird mit dem instanceof-Operator durchgeführt. Die Syntax lautet $objekt instanceof Klasenname oder $objekt instanceof Interfacename. Sowohl für Klassen als auch Interfaces wird also der selbe Operator verwendet. Der Klassename/Interfacename darf nicht von einfachen oder doppelten Anführungszeichen umgeben sein. Zudem muss er immer rechts vom Operator stehen. Links steht entsprechend die Objektinstanz (typischerweise als Variable).
1.1. Kurzes Beispiel
Das einfachstmögliche, sinnvolle Beispiel lautet wohl:
<?php $obj = new stdClass(); if ($obj instanceof stdClass) { echo('$obj ist eine Instanz der Klasse stdClass!'); } else { echo('$obj ist _keine_ Instanz der Klasse stdClass!'); } ?>
$obj ist eine Instanz der Klasse stdClass!
1.2. Etwas umfangreicheres Beispiel
In diesem Beispiel werden zwei Klassen („MyClass” und „MyClassWithInterface”), sowie ein Interface „MyInterface” definiert. „MyClass” erweitert keine andere Klasse und bindet auch kein Interface ein. „MyClassWithInterface” hingegen implementiert das bereits erwähnte Interface „MyInterface”. Es wird nun jeweils von MyClass ($myClass) und MyClassWithInterface ($myClassWithInterface) ein Objekt erzeugt. Beide werden nacheinander per instanceof darauf geprüft, ob sie Instanzen der Klassen oder Interfaces MyClass, MyClassWithInterface, MyInterface oder stdClass sind.
<?php // Ein Beispielinterface interface MyInterface { // leer, da nur Beispiel } // Eine Beispielklasse class MyClass { // leer, da nur Beispiel } // Eine Beispielklasse, die das Beispielinterface einbindet class MyClassWithInterface implements MyInterface { // leer, da nur Beispiel } $myClass = new MyClass(); $myClassWithInterface = new MyClassWithInterface(); // Mit "instanceof" kann geprueft werden, ob sich ein Objekt von // einer bestimmten Klasse ableitet oder genau diese Klasse ist oder // ein bestimmtes Interface einbindet. var_dump($myClass instanceof MyClass); // true var_dump($myClass instanceof MyClassWithInterface); // false var_dump($myClass instanceof MyInterface); // false var_dump($myClass instanceof stdClass); // false var_dump($myClassWithInterface instanceof MyClass); // false var_dump($myClassWithInterface instanceof MyClassWithInterface); // true var_dump($myClassWithInterface instanceof MyInterface); // true var_dump($myClassWithInterface instanceof stdClass); // false ?>
bool(true) bool(false) bool(false) bool(false) bool(false) bool(true) bool(true) bool(false)
1.3. instanceof verlangt nicht, dass die Klassen/Interfaces existieren
Die auf der rechten Seite von instanceof angegebene Klasse bzw. das angegebene Interface muss NICHT existieren. PHP nimmt anstandslos einen Namen an, den es nicht kennt und zu dem auch nirgendwo Code eine Klasse existiert. Das heißt etwas direkter: Wenn man irgendeinen Vertipper im Namen der Klasse oder des Interfaces hat, dann wird PHP bei Erreichen des instanceof-Operators KEINEN Fehler, KEINE Warnung und KEINEN Notice generieren. Also besser jedes instanceof auf Fehler überprüfen. Das gilt auch für eventuell verwendete Namespaces.
<?php namespace Planes { class Boeing747 { } } // globaler Namespace namespace { $plane = new planes\Boeing747(); // Vertipper if ($plane instanceof planes\Beoing747) { echo("Das ist eine Boeing 747!\n"); } else { echo("Keine Boeing 747!\n"); } // Namespace vergessen if ($plane instanceof Beoing747) { echo("Das ist eine Boeing 747!\n"); } else { echo("Keine Boeing 747!\n"); } // Nur das funktioniert // Man beachte, dass sich PHP nicht an der falschen Groß-/Kleinschreibung // des Namespaces stört. if ($plane instanceof planes\Boeing747) { echo("Das ist eine Boeing 747!\n"); } else { echo("Keine Boeing 747!\n"); } } ?>
Keine Boeing 747! Keine Boeing 747! Das ist eine Boeing 747!
2. Mit Reflection auf Klasse testen
Eine weitere Möglichkeit auf bestimmte Klassen zu testen ist es, Reflection zu verwenden. Dazu wird vom zu analysierenden Objekt eine ReflectionClass erzeugt, welche wiederum etliche Methoden anbietet, um das übergebene Objekt auszuwerten. An dieser Stelle ist allerdings nur isSubclassOf($className) interessant. Entsprechend des Namens gibt diese Methode zurück, ob das Objekt zu einer Unterklasse der Klasse mit Namen $className gehört.
<?php interface MyInterface { } class MyClass { } class MyClassWithInterface implements MyInterface { } // Objekt wird erzeugt und an ReflectionClass übergeben $obj = new MyClassWithInterface(); $refl = new ReflectionClass($obj); var_dump($refl->isSubclassOf('MyClass')); var_dump($refl->isSubclassOf('MyInterface')); var_dump($refl->isSubclassOf('stdClass')); ?>
bool(false) bool(true) bool(false)
Im Gegensatz zu instanceof wirft ReflectionClass eine Exception, wenn die an isSubclassOf() übergebene Klasse unbekannt ist. Leider ist ReflectionClass auch gleichzeitig wesentlich langsamer als instanceof und benötigt mehr Zeilen Code in der Anwendung.
3. Für Methodenparameter Klassen/Interfaces vorschreiben
Funktionen/Methoden können vorschreiben, von welcher Klasse sich ihre Parameter ableiten oder welche Interfaces sie implementieren müssen. Dazu muss lediglich der gewünschte Klassen- oder Interfacename vor dem jeweiligen Parameter der Funktion/Methode geschrieben werden. Er darf nicht von einfachen oder doppelten Anführungszeichen umgeben sein. PHP erzeugt einen „catchable fatal error”, wenn nicht die erwartete Klasse/das erwartete Interface übergeben wird. Anders als der Name vermuten lässt, kann man diesen nicht (einfach) per try-catch abfangen.
Achtung: Auch hier wird sich PHP nicht beschweren, wenn der eingegebene Klassen- oder Interfacename unbekannt ist. Fehler werden dann erst entstehen, wenn man versucht, ein eigentlich passendes Objekt zu übergeben.
Hinweis: Diese Vorgaben lassen sich ansonsten nur noch auf Arrays als erwarteter Parameter anwenden. Das erzwingen von Integern, Strings oder ähnlichem ist nicht möglich.
<?php // Auch Funktionen/Methoden dürfen bereits in den Parametern vorschreiben, // welche Klassen übergeben werden dürfen function doSomething(MyClass $mc) { echo("Aufgerufen!\n\n"); } interface MyInterface { } class MyClass { } class MyClassWithInterface implements MyInterface { } $myClass = new MyClass(); $myClassWithInterface = new MyClassWithInterface(); doSomething($myClass); // geht, da $myClass ein Objekt der Klasse MyClass ist doSomething($myClassWithInterface); // erzeugt einen Fatal Error, da die Funktion nur mit MyClass aufgerufen werden darf ?>
Aufgerufen! <br /> <b>Catchable fatal error</b>: Argument 1 passed to doSomething() must be an instance of MyClass, instance of MyClassWithInterface given, called in ...\test.php on line 18 and defined in <b>...\test.php</b> on line <b>4</b><br />
Kommentare (2)
Von neu nach altWir bitten um ihr Verständnis.
// Namespace vergessen
if ($plane instanceof Beoing747) {