Qual é a diferença entre is_a e instanceof?

205

Estou ciente de que instanceofé um operador e que is_aé um método.

O método tem desempenho mais lento? O que você prefere usar?

Daniel
fonte
15
is_a () poderia ser mais lento - mas você pode chamá-lo usando call_user_func () enquanto instanceof não pode ser chamado desta maneira ...
Kamil Tomšík

Respostas:

211

Atualizar

A partir do PHP 5.3.9 , a funcionalidade do is_a()mudou. A resposta original abaixo afirma que is_a() deve aceitar um Objectcomo o primeiro argumento, mas as versões do PHP> = 5.3.9 agora aceitam um terceiro argumento booleano opcional $allow_string(o padrão é false) para permitir comparações de nomes de classes de string:

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

A principal diferença no novo comportamento entre instanceofe is_a()é que instanceofsempre verifica se o destino é um objeto instanciado da classe especificada (incluindo as classes estendidas), ao passo que is_a()apenas exige que o objeto seja instanciado quando o $allow_stringargumento estiver definido como o valor padrão de false.


Original

Na verdade, is_aé uma função, enquanto instanceofé uma construção da linguagem. is_aserá significativamente mais lento (já que possui toda a sobrecarga de execução de uma chamada de função), mas o tempo geral de execução é mínimo em qualquer método.

Ele não é mais descontinuado a partir da versão 5.3, portanto não há nenhuma preocupação lá.

Há uma diferença no entanto. is_asendo uma função leva um objeto como parâmetro 1 e uma string (variável, constante ou literal) como parâmetro 2. Portanto:

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

instanceof usa um objeto como parâmetro 1 e pode usar um nome de classe (variável), instância de objeto (variável) ou identificador de classe (nome da classe gravado sem aspas) como parâmetro 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
fonte
36
Por que is_anão foi reprovado?
Theodore R. Smith
21
@ theodore-r-smith De acordo com a documentação, "não foi reprovado por solicitação popular" php.net/manual/en/migration53.undeprecated.php
Janci 22/10/12
3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell
39
Mais uma coisa a ser observada sobre is_ao instanceofoperador vs é que is_aaceitará expressões para o segundo parâmetro, enquanto instanceof não. Por exemplo, is_a($object, 'Prefix_'.$name)obras enquanto $object instanceof 'Prefix_'.$namenão
Evan Purkhiser
6
is_anunca deveria ter sido preterido em primeiro lugar. É um pouco tarde para consertar agora. O problema é que o instanceofoperador lança erros de sintaxe no PHP 4 e, como is_afoi preterido no momento exato em que o operador foi introduzido, tornou-se impossível escrever código para o PHP 4 e 5 sem gerar um E_STRICT. Você não pode sequer fazer if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }porque ainda iria causar um erro de sintaxe no PHP 4.
meustrus
47

Aqui estão os resultados de desempenho de is_a () e instanceof :

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

A fonte de teste está aqui .

Alexander Yancharuk
fonte
6
Em outras palavras, a diferença é importante apenas se você precisar economizar ~ 0,015 segundos por 10000 usos.
CJ Dennis
1
A partir de php 7não há diferença.
MAX
@CJDennis Por experiência, quando todo mundo pensa assim, o produto final será mais lento que o esperado. (Soft + OS + servidores não otimizados). Lembre-se de que o tempo adicionado nem sempre é linear, mas pode ser exponencial. Tenha sempre em mente o desempenho.
Toto
@Toto Existe uma excelente postagem no blog sobre o que desenvolvedores experientes podem aprender com iniciantes. Espero que você possa vê-lo no canto superior direito. Cuidado com a otimização prematura! Resolva apenas problemas de tempo depois que eles se tornarem problemas ! Se o desempenho for aceitável, não perca tempo alterando-o!
CJ Dennis
10

instanceofpode ser usado com outras instâncias de objeto, o nome da classe ou uma interface. Eu não acho que is_a()funcione com interfaces (apenas uma string representando um nome de classe), mas me corrija se isso acontecer. (Atualização: consulte https://gist.github.com/1455148 )

Exemplo do 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'

saídas:

bool(true)
bool(true)
bool(false)
Lotus Notes
fonte
3
is_afaz o trabalho com interfaces da mesma forma que instanceof(eu ia dizer a mesma coisa, mas eu verifiquei antes de enviar, e ele faz, de facto trabalho) ...
ircmaxell
2
-1, resuma a atualização em vez de apenas vincular a uma essência. Isso é inútil para as pessoas que tentam aprender.
precisa
5

Em relação à resposta de ChrisF, is_a() não é mais preterido a partir do PHP 5.3.0. Acho que é sempre mais seguro procurar a fonte oficial para coisas assim.

Com relação à sua pergunta, Daniel, não posso dizer sobre as diferenças de desempenho, mas parte disso se resume à legibilidade e com a qual você acha mais fácil trabalhar.

Além disso, há alguma discussão sobre a confusão em torno negando uma instanceofverificação vs is_a(). Por exemplo, para instanceofvocê faria:

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

vs o seguinte para is_a():

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

ou

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

Editar Parece que ChrisF excluiu sua resposta, mas a primeira parte da minha resposta ainda permanece.

Mike Branski
fonte
5

Além da velocidade, outra diferença importante é como eles lidam com casos extremos.

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.

Portanto, is_a () destaca possíveis erros enquanto instanceof os suprime.

Csongor Halmai
fonte
2

A otimização é mínima. E as micro-otimizações nunca são uma resposta muito boa, diante da legibilidade, compreensão e estabilidade do código.

(Pessoalmente, prefiro instanceof , mas a escolha é sua;))

A principal diferença é a possibilidade de usar o nome direto da classe com instanceof

$ uma instância do MyClass

é mais curto que

is_a ($ a, MyClass :: class)

(ok ... não é trivial.)

A coloração sintaxe entre instanceof (estrutura da linguagem) e is_a também é útil (para mim). deixando a função cor para operações maiores. E para uso único em if, instanceof não precisa de mais parênteses.

Nota: é claro que, em vez de MyClass :: class, você pode usar uma string direta mais curta:

is_a ($ a, 'MinhaClasse')

Mas usar seqüência direta em um código não é uma boa prática .

A coleta sintaxe é melhor e mais útil se você puder fazer a diferença entre nomes simples de sequência e de classe. E é mais fácil alterar os nomes com o nome da classe constante. Especialmente se você usar espaço para nome com alias.

Então, por que usar is_a () ?

Pela mesma razão: legibilidade e incompreensibilidade. (a escolha é sua) Especialmente quando usado com ! ou outros operadores booleanos: is_a parece mais prático entre parênteses.

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

é mais legível que:

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

Outro bom motivo é quando você precisa usar o retorno de chamada nas funções. (como array_map ...) instanceof não é uma função, é uma construção de linguagem, portanto você não pode usá-lo como retorno de chamada.

Nesses casos, is_a pode ser útil

Titsta
fonte
1

Não posso falar por desempenho - ainda não medi nada - mas, dependendo do que você está tentando, há limitações instanceof. Confira minha pergunta, recentemente, sobre isso:

PHP 'instanceof' falhando com constante de classe

Acabei usando is_a. Gosto mais da estrutura instanceof(acho melhor) e continuarei a usá-la onde puder.

Nathan Loding
fonte
1

Aqui estão os resultados de desempenho obtidos aqui :

instanceof é mais rápido.

Funções

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

Vezes (executado 5000 vezes cada)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)
dayuloli
fonte
1

Há um cenário em que apenas is_a()funciona e instanceoffalhará.

instanceof espera um nome de classe literal ou uma variável que seja um objeto ou uma string (com o nome de uma classe) como seu argumento correto.

Mas se você deseja fornecer a sequência de um nome de classe a partir de uma chamada de função, ela não funcionará e resultará em um erro de sintaxe.

No entanto, o mesmo cenário funciona bem is_a().

Exemplo:

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

Isso é baseado no PHP 7.2.14.

Erik Kalkoken
fonte