Jaka jest różnica między is_a a instanceof?

205

Wiem, że instanceofto operator i to is_ajest metoda.

Czy metoda działa wolniej? Z czego wolisz korzystać?

Daniel
źródło
15
is_a () może działać wolniej - ale można go wywoływać za pomocą call_user_func (), podczas gdy instanceof nie może być wywoływany w ten sposób ...
Kamil Tomšík

Odpowiedzi:

211

Aktualizacja

Od wersji PHP 5.3.9is_a() zmieniła się funkcjonalność . Oryginalna odpowiedź poniżej stwierdza, że is_a() musi przyjąć Objectjako pierwszy argument, ale wersje PHP> = 5.3.9 akceptują teraz opcjonalny trzeci argument boolowski $allow_string(domyślnie to false), aby zamiast tego umożliwić porównanie nazw klas łańcuchów:

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);

Kluczowa różnica w nowym zachowaniu między instanceofi is_a()polega na tym, instanceofże zawsze sprawdzi, czy obiekt docelowy jest utworzonym obiektem określonej klasy (w tym klas rozszerzających), podczas gdy is_a()wymaga tylko utworzenia obiektu, gdy $allow_stringargument jest ustawiony na wartość domyślną false.


Oryginalny

W rzeczywistości is_ajest funkcją, podczas gdy instanceofjest konstrukcją językową. is_abędzie znacznie wolniejszy (ponieważ ma cały narzut związany z wykonaniem wywołania funkcji), ale ogólny czas wykonania jest minimalny w każdej z metod.

Nie jest już przestarzałe od 5.3, więc nie ma się co martwić.

Jest jednak jedna różnica. is_abycie funkcją przyjmuje obiekt jako parametr 1, a ciąg (zmienny, stały lub literał) jako parametr 2. Zatem:

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

instanceof przyjmuje obiekt jako parametr 1 i może przyjmować nazwę klasy (zmienną), instancję obiektu (zmienną) lub identyfikator klasy (nazwę klasy zapisaną bez cudzysłowów) jako parametr 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
źródło
36
Dlaczego był is_anieaktualny?
Theodore R. Smith
21
@ theodore-r-smith Zgodnie z dokumentacją „nie została wycofana z popularnej prośby” php.net/manual/en/migration53.undeprecated.php
Janci
3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell
39
Jeszcze jedną rzeczą wartą uwagi na temat is_avs instanceofoperator jest to, że is_aakceptuje wyrażenia dla drugiego parametru, podczas gdy instanceof nie będzie. Na przykład is_a($object, 'Prefix_'.$name)działa, podczas gdy $object instanceof 'Prefix_'.$namenie działa
Evan Purkhiser
6
is_anigdy nie powinien był być przestarzały. Jednak teraz jest trochę za późno, aby to naprawić. Problem polega na tym, że instanceofoperator zgłasza błędy składniowe w PHP 4, a ponieważ is_abył przestarzały w tym samym czasie, w którym wprowadzono operatora, stało się niemożliwe napisanie kodu zarówno dla PHP 4, jak i 5 bez rzucania E_STRICT. Nie możesz tego zrobić, if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }ponieważ nadal powoduje błąd składniowy w PHP 4.
Meustrus
47

Oto wyniki wydajności is_a () i instanceof :

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

Źródło testu jest tutaj .

Alexander Yancharuk
źródło
6
Innymi słowy, różnica jest ważna tylko wtedy, gdy trzeba zaoszczędzić ~ 0,015 sekundy na 10000 zastosowań.
CJ Dennis
1
Jak na razie php 7nie ma różnicy.
MAX
@CJDennis Z doświadczenia wynika, że ​​gdy wszyscy tak myślą, końcowy produkt będzie wolniejszy niż oczekiwano. (Serwery Soft + OS + niezoptymalizowane). Pamiętaj, że dodany czas nie zawsze jest liniowy, ale może być wykładniczy. Zawsze miej na uwadze wydajność.
Toto
@Toto Istnieje doskonały wpis na blogu o tym, czego doświadczeni programiści mogą nauczyć się od początkujących. Mam nadzieję, że możesz to zobaczyć w prawym górnym rogu. Uwaga na przedwczesną optymalizację! Rozwiązuj problemy z synchronizacją dopiero, gdy stają się problemami ! Jeśli wydajność jest możliwa do zaakceptowania, nie marnuj czasu na jej zmianę!
CJ Dennis,
10

instanceofmoże być używany z innymi instancjami obiektów, nazwą klasy lub interfejsem. Nie sądzę, że is_a()działa z interfejsami (tylko ciąg znaków reprezentujący nazwę klasy), ale popraw mnie, jeśli to działa. (Aktualizacja: patrz https://gist.github.com/1455148 )

Przykład z 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'

wyjścia:

bool(true)
bool(true)
bool(false)
Lotus Notes
źródło
3
is_adziała z interfejsami w taki sam sposób, jak instanceof(chciałem powiedzieć to samo, ale sprawdziłem to przed przesłaniem i rzeczywiście działa) ...
ircmaxell
2
-1, proszę streścić aktualizację, a nie tylko link do istoty. To nie jest pomocne dla osób próbujących się uczyć.
Erick Robertson,
5

Jeśli chodzi o odpowiedź ChrisF, is_a() nie jest już przestarzała od PHP 5.3.0. Uważam, że zawsze bezpieczniej jest korzystać z oficjalnego źródła takich rzeczy.

Jeśli chodzi o twoje pytanie, Daniel, nie mogę powiedzieć o różnicach w wydajności, ale część z nich sprowadza się do czytelności i z którą łatwiej ci się pracuje.

Ponadto, istnieje pewna dyskusja na temat zamieszania wokół negując to instanceofczek vs is_a(). Na przykład dla instanceofciebie zrobiłbyś:

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

vs następujące dla is_a():

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

lub

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

Edytuj Wygląda na to, że ChrisF usunął swoją odpowiedź, ale pierwsza część mojej odpowiedzi nadal obowiązuje.

Mike Branski
źródło
5

Oprócz prędkości, inną ważną różnicą jest sposób, w jaki obsługują przypadki krawędzi.

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.

Zatem is_a () podkreśla możliwe błędy, a instanceof je eliminuje.

Csongor Halmai
źródło
2

Optymalizacja jest minimalna. A mikrooptymalizacje nigdy nie są naprawdę dobrą odpowiedzią, pomimo czytelności, zrozumiałości i stabilności kodu.

(Ja osobiście preferujemy instancją , ale wybór należy do Ciebie;))

Główną różnicą jest możliwość użycia bezpośredniej nazwy klasy z instanceof

$ wystąpienie MyClass

jest krótszy niż

is_a ($ a, MyClass :: class)

(ok ... to nie jest banalne.)

Przydatne jest również składniowe kolorowanie między instanceof (struktura językowa) a is_a (dla mnie). pozwalając kolorowi funkcji na większe operacje. I do jednorazowego użytku, jeśli instanceof nie potrzebuje więcej nawiasów.

Uwaga: Oczywiście zamiast MyClass :: class możesz użyć krótszego ciągu bezpośredniego:

is_a ($ a, „MyClass”)

Ale użycie bezpośredniego ciągu w kodzie nie jest dobrą praktyką .

Składnia składniowa jest lepsza i bardziej użyteczna, jeśli można zrobić różnicę między prostymi nazwami łańcuchów i klas. I łatwiej jest zmieniać nazwy za pomocą stałej nazwy klasy. Zwłaszcza jeśli używasz przestrzeni nazw z aliasem.

Wy użyj is_a () ?

Z tej samej racji: czytelność i nierozpoznawalność. (wybór należy do Ciebie) Specjalnie, gdy używasz go ! lub inne operatory logiczne: is_a wydaje się bardziej praktyczne z nawiasami.

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

jest bardziej czytelny niż:

if ($ a AND (! ($ a instanceof MyClass) LUB ((a intanceof MyOtherClass))))

Innym dobrym powodem jest konieczność użycia funkcji zwrotnej w funkcjach. (jak array_map …) instanceof nie jest funkcją, jest konstrukcją językową, więc nie można jej użyć jako wywołania zwrotnego.

W takich przypadkach użyteczne może być is_a

Titsta
źródło
1

Nie mogę mówić o wydajności - jeszcze niczego nie mierzyłem - ale w zależności od tego, co próbujesz, istnieją ograniczenia instanceof. Sprawdź moje pytanie na ten temat:

PHP „instanceof” zawodzi ze stałą klasy

Skończyło się na tym, że używam is_a. Podoba mi się struktura instanceoflepiej (myślę, że jest ładniejsza) i nadal będę jej używać tam, gdzie mogę.

Nathan Loding
źródło
1

Oto wyniki wydajności uzyskane stąd :

instanceof jest szybszy.

Funkcje

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';
}

Razy (uruchom 5000 razy każdy)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)
dayuloli
źródło
1

Istnieje scenariusz, w którym is_a()działa tylko i instanceofzawiedzie.

instanceof oczekuje literałowej nazwy klasy lub zmiennej, która jest albo obiektem albo łańcuchem (z nazwą klasy) jako właściwym argumentem.

Ale jeśli chcesz podać ciąg nazwy klasy z wywołania funkcji, nie będzie działać i spowoduje błąd składniowy.

Jednak ten sam scenariusz działa dobrze z is_a().

Przykład:

<?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()));

Jest to oparte na PHP 7.2.14.

Erik Kalkoken
źródło