Ist es bei einer gegebenen Klasseninstanz möglich festzustellen, ob sie eine bestimmte Schnittstelle implementiert? Soweit ich weiß, gibt es keine eingebaute Funktion, um dies direkt zu tun. Welche Möglichkeiten habe ich (falls vorhanden)?
Prüfen, ob die Klasse einer Instanz eine Schnittstelle implementiert?
interface IInterface
{
}
class TheClass implements IInterface
{
}
$cls = new TheClass();
if ($cls instanceof IInterface) {
echo "yes";
}
Sie können den „instanceof“-Operator verwenden. Um es zu verwenden, ist der linke Operand eine Klasseninstanz und der rechte Operand eine Schnittstelle. Es gibt true zurück, wenn das Objekt eine bestimmte Schnittstelle implementiert.
-
Beachten Sie, dass dies nicht nützlich ist, wenn Sie versuchen, den Konstruktor der Klasse zu bestimmen
– AaA
23. November 2020 um 8:12 Uhr
Jess Telford
Wie daraus hervorgeht, können Sie verwenden class_implements()
. Genau wie bei Reflection können Sie damit den Klassennamen als Zeichenfolge angeben und benötigen keine Instanz der Klasse:
interface IInterface
{
}
class TheClass implements IInterface
{
}
$interfaces = class_implements('TheClass');
if (isset($interfaces['IInterface'])) {
echo "Yes!";
}
class_implements()
ist Teil der SPL-Erweiterung.
Sehen: http://php.net/manual/en/function.class-implements.php
Leistungstests
Einige einfache Leistungstests zeigen die Kosten jedes Ansatzes:
Gegeben eine Instanz eines Objekts
Object construction outside the loop (100,000 iterations) ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 140 ms | 290 ms | 35 ms | '--------------------------------------------' Object construction inside the loop (100,000 iterations) ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 182 ms | 340 ms | 83 ms | Cheap Constructor | 431 ms | 607 ms | 338 ms | Expensive Constructor '--------------------------------------------'
Gegeben ist nur ein Klassenname
100,000 iterations ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 149 ms | 295 ms | N/A | '--------------------------------------------'
Wo das teure __construct() ist:
public function __construct() {
$tmp = array(
'foo' => 'bar',
'this' => 'that'
);
$in = in_array('those', $tmp);
}
Diese Tests basieren auf dieser einfache Code.
Bill Karwin
nlaq weist darauf hin instanceof
kann verwendet werden, um zu testen, ob das Objekt eine Instanz einer Klasse ist, die eine Schnittstelle implementiert.
Aber instanceof
unterscheidet nicht zwischen einem Klassentyp und einer Schnittstelle. Sie wissen nicht, ob das Objekt a ist Klasse das heißt zufällig IInterface
.
Sie können dies auch mit der Reflection-API in PHP genauer testen:
$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
print "Yep!\n";
}
-
Dies kann für “statische” Klassen verwendet werden
– Znarkus
23. August 2009 um 9:41 Uhr
-
-
@therefromhere: Danke, guter Tipp. Das ist Teil der SPL-Erweiterung. Meine Antwort verwendete die Reflection-Erweiterung.
– Bill Karwin
15. November 2011 um 22:01 Uhr
-
Wenn Sie Namespaces verwenden, besteht keine Mehrdeutigkeit zwischen Schnittstellen und Klassen mit demselben Namen, und Sie können sie sicher verwenden
instanceof
wieder.– Grippe
21. März 2012 um 16:18 Uhr
-
+1 für
class_implements()
da es offensichtlich schneller ist, class_implements und dann in_array aufzurufen, anstatt eine vollständige Reflexion vorzunehmen– Nikolaus
17. März 2017 um 14:20 Uhr
d.raev
Nur um zukünftige Suchen zu erleichtern ist_unterklasse_von ist auch eine gute Variante (für PHP 5.3.7+):
if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
echo 'I can do it!';
}
SirPilan
Aktualisieren
Das is_a
Funktion fehlt hier als Alternative.
Ich habe einige Leistungstests durchgeführt, um zu überprüfen, welche der angegebenen Methoden am leistungsfähigsten ist.
Ergebnisse über 100.000 Iterationen
instanceof [object] took 7.67 ms | + 0% | ..........
is_a [object] took 12.30 ms | + 60% | ................
is_a [class] took 17.43 ms | +127% | ......................
class_implements [object] took 28.37 ms | +270% | ....................................
reflection [class] took 34.17 ms | +346% | ............................................
Einige Punkte hinzugefügt, um den Unterschied tatsächlich zu “fühlen”.
Dadurch generiert: https://3v4l.org/8Cog7
Fazit
Falls Sie eine haben Objekt prüfen, verwenden instanceof
wie in der akzeptierten Antwort erwähnt.
Falls Sie eine haben Klasse prüfen, verwenden is_a
.
Bonus
In Anbetracht des Falls, dass Sie eine Klasse basierend auf einer Schnittstelle, die Sie benötigen, instanziieren möchten, ist dies besser zu verwenden is_a
. Es gibt nur eine Ausnahme – wenn der Konstruktor leer ist.
Beispiel:
is_a(<className>, <interfaceName>, true);
Es wird zurückkehren bool
. Der dritte Parameter “allow_string” ermöglicht es, Klassennamen zu überprüfen ohne Instanziieren der Klasse.
-
Das ist schön, hinzugefügt
is_subclass_of
zum Drehbuch. 3v4l.org/FY4re– Fegefeuer
15. Dezember 2021 um 16:42 Uhr
Starx
Sie können auch Folgendes tun
public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
//.....
}
Es wird einen behebbaren Fehler auslösen, wenn die $objectSupposedToBeImplementing
nicht umsetzt YourInterface
Schnittstelle.
-
Das ist schön, hinzugefügt
is_subclass_of
zum Drehbuch. 3v4l.org/FY4re– Fegefeuer
15. Dezember 2021 um 16:42 Uhr