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?
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?
Respostas:
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 Object
como 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 instanceof
e is_a()
é que instanceof
sempre 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_string
argumento 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_a
será 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_a
sendo 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
is_a
não foi reprovado?
$class = 'Foo'; var_dump($obj instanceof $class);
is_a
o instanceof
operador vs é que is_a
aceitará expressões para o segundo parâmetro, enquanto instanceof não. Por exemplo, is_a($object, 'Prefix_'.$name)
obras enquanto $object instanceof 'Prefix_'.$name
não
is_a
nunca deveria ter sido preterido em primeiro lugar. É um pouco tarde para consertar agora. O problema é que o instanceof
operador lança erros de sintaxe no PHP 4 e, como is_a
foi 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.
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 .
php 7
não há diferença.
instanceof
pode ser usado com outras instâncias de objeto, o nome da classe ou uma interface. Eu não acho que (Atualização: consulte https://gist.github.com/1455148 )is_a()
funcione com interfaces (apenas uma string representando um nome de classe), mas me corrija se isso acontecer.
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)
is_a
faz 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) ...
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 instanceof
verificação vs is_a()
. Por exemplo, para instanceof
você 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.
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.
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
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.
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)
Há um cenário em que apenas is_a()
funciona e instanceof
falhará.
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.