Was ist der Unterschied zwischen is_a und instanceof?

205

Ich bin mir bewusst, dass instanceof ein Operator und is_aeine Methode ist.

Ist die Leistung der Methode langsamer? Was würdest du lieber benutzen?

Daniel
quelle
15
is_a () könnte langsamer sein - aber Sie können es mit call_user_func () aufrufen, während instanceof nicht auf diese Weise aufgerufen werden kann ...
Kamil Tomšík

Antworten:

211

Aktualisieren

Ab PHP 5.3.9 hat sich die Funktionalität von is_a()geändert. Die ursprüngliche Antwort unten besagt, dass ein als erstes Argument akzeptiert werden is_a() muss , ObjectPHP-Versionen> = 5.3.9 akzeptieren jetzt jedoch ein optionales drittes boolesches Argument $allow_string(standardmäßig false), um stattdessen Vergleiche von Zeichenfolgenklassennamen zu ermöglichen:

class MyBaseClass {}
class MyExtendingClass extends MyBaseClass {}

// Original behavior, evaluates to false.
is_a(MyExtendingClass::class, MyBaseClass::class);

// New behavior, evaluates to true.
is_a(MyExtendingClass::class, MyBaseClass::class, true);

Der Hauptunterschied im neuen Verhalten zwischen instanceofund is_a()besteht darin, dass instanceofimmer überprüft wird, ob das Ziel ein instanziiertes Objekt der angegebenen Klasse ist (einschließlich erweiterter Klassen), während is_a()das Objekt nur instanziiert werden muss, wenn das $allow_stringArgument auf den Standardwert von gesetzt ist false.


Original

Eigentlich is_aist eine Funktion, während instanceofes sich um ein Sprachkonstrukt handelt. is_awird erheblich langsamer sein (da der gesamte Aufwand für die Ausführung eines Funktionsaufrufs anfällt), aber die Gesamtausführungszeit ist bei beiden Methoden minimal.

Ab 5.3 ist es nicht mehr veraltet, daher gibt es dort keine Sorgen mehr.

Es gibt jedoch einen Unterschied. is_aAls Funktion wird ein Objekt als Parameter 1 und eine Zeichenfolge (Variable, Konstante oder Literal) als Parameter 2 verwendet. Also:

is_a($object, $string); // <- Only way to call it

instanceof Nimmt ein Objekt als Parameter 1 und kann einen Klassennamen (Variable), eine Objektinstanz (Variable) oder eine Klassenkennung (Klassenname ohne Anführungszeichen) als Parameter 2 verwenden.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
quelle
36
Warum wurde nicht is_averaltet?
Theodore R. Smith
21
@ theodore-r-smith Laut der Dokumentation "wurde es auf vielfachen Wunsch nicht mehr geschätzt" php.net/manual/en/migration53.undeprecated.php
Janci
3
@ Danip$class = 'Foo'; var_dump($obj instanceof $class);
Ircmaxell
39
Eine weitere Sache, die Sie is_agegenüber dem instanceofOperator beachten sollten , ist, dass is_aAusdrücke für den zweiten Parameter akzeptiert werden, während dies nicht der Fall ist. Zum Beispiel is_a($object, 'Prefix_'.$name)funktioniert, während $object instanceof 'Prefix_'.$namenicht
Evan Purkhiser
6
is_asollte niemals in erster Linie veraltet sein. Es ist allerdings etwas spät, das Problem jetzt zu beheben. Das Problem ist, dass der instanceofOperator Syntaxfehler in PHP 4 is_aauslöst. Da dies genau zur gleichen Zeit veraltet war, als der Operator eingeführt wurde, war es unmöglich, Code für PHP 4 und 5 zu schreiben, ohne ein E_STRICT herumzuwerfen. Sie können nicht einmal tun, if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }weil es immer noch einen Syntaxfehler in PHP 4 verursachen würde.
Meustrus
47

Hier sind die Leistungsergebnisse von is_a () und instanceof :

Test name       Repeats         Result          Performance     
instanceof      10000           0.028343 sec    +0.00%
is_a()          10000           0.043927 sec    -54.98%

Testquelle ist hier .

Alexander Yancharuk
quelle
6
Mit anderen Worten, der Unterschied ist nur wichtig, wenn Sie pro 10000 Verwendungen ~ 0,015 Sekunden sparen müssen.
CJ Dennis
1
Ab php 7gibt es keinen Unterschied.
MAX
@CJDennis Erfahrungsgemäß ist das Endprodukt langsamer als erwartet, wenn alle so denken. (Soft + OS + Server nicht optimiert). Denken Sie daran, dass die hinzugefügte Zeit nicht immer linear ist, sondern exponentiell sein kann. Denken Sie immer an Leistung.
Toto
@Toto Es gibt einen ausgezeichneten Blog-Beitrag darüber, was erfahrene Entwickler von Anfängern lernen können. Hoffentlich können Sie es oben rechts sehen. Vorsicht vor vorzeitiger Optimierung! Lösen Sie Timing-Probleme erst, wenn sie zu Problemen geworden sind ! Wenn die Leistung so akzeptabel ist, verbringen Sie keine Zeit damit, sie zu ändern!
CJ Dennis
10

instanceofkann mit anderen Objektinstanzen, dem Klassennamen oder einer Schnittstelle verwendet werden. Ich denke nicht, dass is_a()das mit Schnittstellen funktioniert (nur eine Zeichenfolge, die einen Klassennamen darstellt), aber korrigiere mich, wenn dies der Fall ist. (Update: Siehe https://gist.github.com/1455148 )

Beispiel von php.net :

interface MyInterface
{
}

class MyClass implements MyInterface
{
}

$a = new MyClass;
$b = new MyClass;
$c = 'MyClass';
$d = 'NotMyClass';

var_dump($a instanceof $b); // $b is an object of class MyClass
var_dump($a instanceof $c); // $c is a string 'MyClass'
var_dump($a instanceof $d); // $d is a string 'NotMyClass'

Ausgänge:

bool(true)
bool(true)
bool(false)
Lotus Notes
quelle
3
is_afunktioniert mit Schnittstellen genauso wie instanceof(ich wollte dasselbe sagen, aber ich habe es vor dem Absenden überprüft, und es funktioniert tatsächlich) ...
ircmaxell
2
-1 Bitte fassen Sie das Update zusammen, anstatt nur auf einen Kern zu verlinken. Das ist für Menschen, die versuchen zu lernen, nicht hilfreich.
Erick Robertson
5

In Bezug auf die Antwort von ChrisF ist ab PHP 5.3.0 is_a() nicht mehr veraltet . Ich finde es immer sicherer, sich für solche Dinge an die offizielle Quelle zu wenden.

In Bezug auf Ihre Frage, Daniel, kann ich nichts über die Leistungsunterschiede sagen, aber ein Teil davon hängt von der Lesbarkeit ab, mit der Sie leichter arbeiten können.

Auch gibt es einige Diskussionen über die Verwirrung um negiert einen instanceofScheck vs is_a(). Zum Beispiel instanceofwürden Sie tun:

<?php
if( !($a instanceof A) ) { //... }
?>

vs die folgenden für is_a():

<?php
if( !is_a($a, 'A' ) { //... }
?>

oder

<?php
if( is_a($a, 'A') === FALSE) { //... }
?>

Bearbeiten Sieht so aus, als hätte ChrisF seine Antwort gelöscht, aber der erste Teil meiner Antwort steht noch.

Mike Branski
quelle
5

Neben der Geschwindigkeit ist ein weiterer wichtiger Unterschied, wie sie mit Kantenfällen umgehen.

is_a($x1, $x2) // fatal error if x2 is not a string nor an object
$x1 instanceof $x2  // returns false even if $x2 is int, undefined, etc.

Is_a () hebt mögliche Fehler hervor, während die Instanz sie unterdrückt.

Csongor Halmai
quelle
2

Die Optimierung ist minimal. Und Mikrooptimierungen sind angesichts der Lesbarkeit, Verständlichkeit und Stabilität des Codes niemals eine wirklich gute Antwort.

(Ich persönlich bevorzuge eine Instanz davon , aber die Wahl liegt bei Ihnen;))

Der Hauptunterschied besteht in der Möglichkeit, den direkten Klassennamen mit instanceof zu verwenden

$ eine Instanz von MyClass

ist kürzer als

is_a ($ a, MyClass :: class)

(ok ... es ist nicht trivial.)

Die syntaktische Färbung zwischen instanceof (Sprachstruktur) und is_a ist ebenfalls nützlich (für mich). Funktionsfarbe für größere Operationen verwenden. Und für den einmaligen Gebrauch, wenn zum Beispiel nicht mehr Klammern benötigt werden.

Hinweis: Natürlich können Sie anstelle von MyClass :: class auch eine kürzere direkte Zeichenfolge verwenden:

is_a ($ a, 'MyClass')

Die Verwendung einer direkten Zeichenfolge in einem Code ist jedoch keine gute Vorgehensweise .

Die syntaktische Sortierung ist besser und nützlicher, wenn Sie zwischen einfachen Zeichenfolgen- und Klassennamen unterscheiden können. Und es ist einfacher, Namen mit konstantem Klassennamen zu ändern. Besonders, wenn Sie einen Namespace mit Alias ​​verwenden.

Also, warum is_a () verwenden ?

Aus demselben Grund: Lesbarkeit und Verständlichkeit. (Sie haben die Wahl) Spezial bei Verwendung mit ! oder andere boolesche Operatoren: is_a scheint mit Klammern praktischer zu sein.

if ($ a AND (! is_a ($ a, MyClass :: class) ODER is_a ($ a, MyOtherClass :: class)))

ist besser lesbar als:

if ($ a AND (! ($ a Instanz von MyClass) OR ($ a Intance von MyOtherClass)))

Ein weiterer guter Grund ist, wenn Sie Rückruf in Funktionen verwenden müssen. (wie array_map …) instanceof ist keine Funktion, sondern ein Sprachkonstrukt, daher können Sie es nicht als Rückruf verwenden.

In diesen Fällen kann is_a nützlich sein

Titsta
quelle
1

Ich kann nicht für Leistung sprechen - ich habe noch nichts gemessen - aber je nachdem, was Sie versuchen, gibt es Einschränkungen bei instanceof. Schauen Sie sich erst kürzlich meine Frage dazu an:

PHP 'instanceof' schlägt mit Klassenkonstante fehl

Ich habe is_astattdessen verwendet. Ich mag die Struktur von instanceofbesser (ich denke, sie liest sich besser) und werde sie weiterhin verwenden, wo ich kann.

Nathan Loding
quelle
1

Hier sind die Leistungsergebnisse, die Sie hier erhalten :

instanceof ist schneller.

Funktionen

function method_1($a = null) { 
    return is_object($a) && is_a($a, 'Example');
}

function method_2($a = null) {
    return is_a((object) $a, 'Example');
}

function method_3($a = null) {
    return $a instanceof 'Example';
}

Zeiten (jeweils 5000 Mal ausgeführt)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)
Dayuloli
quelle
1

Es gibt ein Szenario, in dem nur is_a()funktioniert und instanceoffehlschlägt.

instanceof erwartet einen Literalklassennamen oder eine Variable, die entweder ein Objekt oder eine Zeichenfolge (mit dem Namen einer Klasse) als rechtes Argument ist.

Wenn Sie jedoch die Zeichenfolge eines Klassennamens aus einem Funktionsaufruf bereitstellen möchten, funktioniert dies nicht und führt zu einem Syntaxfehler.

Das gleiche Szenario funktioniert jedoch einwandfrei is_a().

Beispiel:

<?php

function getClassName() : string
{
    return "Foobar";
}

class Foobar
{
    private $xyz;

}

$x = new Foobar();

// this works of course
var_dump($x instanceof Foobar);

// this creates a syntax error
var_dump($x instanceof getClassName());

// this works
var_dump(is_a($x, getClassName()));

Dies basiert auf PHP 7.2.14.

Erik Kalkoken
quelle