¿Cuál es la diferencia entre is_a y instanceof?

205

Soy consciente de que instanceofes un operador y que is_aes un método.

¿Es el método más lento en rendimiento? ¿Qué preferirías usar?

Daniel
fuente
15
is_a () podría ser más lento, pero puede llamarlo usando call_user_func () mientras que instanceof no se puede llamar de esta manera ...
Kamil Tomšík

Respuestas:

211

Actualizar

A partir de PHP 5.3.9 , la funcionalidad de is_a()ha cambiado. La respuesta original a continuación establece que is_a() debe aceptar un Objectcomo primer argumento, pero las versiones de PHP> = 5.3.9 ahora aceptan un tercer argumento booleano opcional $allow_string(por defecto false) para permitir comparaciones de nombres de clase de cadena en su lugar:

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

La diferencia clave en el nuevo comportamiento entre instanceofy is_a()es que instanceofsiempre comprobará que el objetivo es un objeto instanciado de la clase especificada (incluidas las clases extendidas), mientras que is_a()solo requiere que el objeto se instancia cuando el $allow_stringargumento se establece en el valor predeterminado de false.


Original

En realidad, is_aes una función, mientras que instanceofes una construcción del lenguaje. is_aserá significativamente más lento (ya que tiene toda la sobrecarga de ejecutar una llamada de función), pero el tiempo de ejecución general es mínimo en cualquier método.

Ya no está en desuso a partir de 5.3, por lo que no hay que preocuparse.

Sin embargo, hay una diferencia. is_aser una función toma un objeto como parámetro 1 y una cadena (variable, constante o literal) como parámetro 2. Entonces:

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

instanceof toma un objeto como parámetro 1 y puede tomar un nombre de clase (variable), instancia de objeto (variable) o identificador de clase (nombre de clase escrito sin comillas) como parámetro 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
fuente
36
¿Por qué fue is_adesaprobado?
Theodore R. Smith
21
@ Theodore-r-Smith De acuerdo con la documentación que "se ha undeprecated por petición popular" php.net/manual/en/migration53.undeprecated.php
Janci
3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell
39
Una cosa más a tener en cuenta sobre is_ael instanceofoperador es que is_aaceptará expresiones para el segundo parámetro, mientras que instancia de wont. Por ejemplo, is_a($object, 'Prefix_'.$name)funciona mientras $object instanceof 'Prefix_'.$nameno funciona
Evan Purkhiser
66
is_anunca debería haber sido desaprobado en primer lugar. Sin embargo, es un poco tarde para arreglarlo ahora. El problema es que el instanceofoperador arroja errores de sintaxis en PHP 4, y dado que is_afue desaprobado exactamente al mismo tiempo que se introdujo el operador, se hizo imposible escribir código para PHP 4 y 5 sin lanzar un E_STRICT. Ni siquiera puede hacerlo if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }porque aún causaría un error de sintaxis en PHP 4.
meustrus
47

Aquí están los resultados de rendimiento de is_a () y instanceof :

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

La fuente de prueba está aquí .

Alexander Yancharuk
fuente
66
En otras palabras, la diferencia solo es importante si necesita guardar ~ 0.015 segundos por cada 10000 usos.
CJ Dennis
1
A partir de php 7no hay diferencia.
MAX
@CJDennis Por experiencia, cuando todos piensan así, el producto final será más lento de lo esperado. (Soft + OS + servidores sin optimizar). Recuerde que el tiempo agregado no siempre es lineal, pero puede ser exponencial. Siempre tenga en cuenta el rendimiento.
Toto
@Toto Hay una excelente publicación de blog sobre lo que los desarrolladores experimentados pueden aprender de los principiantes. Espero que puedas verlo en la parte superior derecha. ¡Cuidado con la optimización prematura! ¡Solo resuelva los problemas de tiempo después de que se hayan convertido en problemas ! Si el rendimiento es aceptable como es, ¡no pierdas el tiempo en cambiarlo!
CJ Dennis
10

instanceofse puede usar con otras instancias de objetos, el nombre de la clase o una interfaz. No creo que is_a()funcione con interfaces (solo una cadena que representa un nombre de clase), pero corrígeme si lo hace. (Actualización: consulte https://gist.github.com/1455148 )

Ejemplo de 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'

salidas:

bool(true)
bool(true)
bool(false)
Lotus Notes
fuente
3
is_afunciona con interfaces de la misma manera que instanceof(iba a decir lo mismo, pero lo verifiqué antes de enviarlo, y de hecho funciona) ...
ircmaxell
2
-1 por favor resuma la actualización en lugar de simplemente vincularla a una esencia. Eso no ayuda a las personas que intentan aprender.
Erick Robertson
5

En lo que respecta a la respuesta de ChrisF, is_a() ya no está en desuso a partir de PHP 5.3.0. Creo que siempre es más seguro recurrir a la fuente oficial para cosas como esta.

Con respecto a su pregunta, Daniel, no puedo decir sobre las diferencias de rendimiento, pero parte de esto se reducirá a la legibilidad y con la que le resultará más fácil trabajar.

Además, existe cierto debate acerca de la confusión en torno a la negación de un instanceofcheque vs is_a(). Por ejemplo, para instanceofusted haría:

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

vs lo siguiente para is_a():

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

o

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

Editar Parece que ChrisF eliminó su respuesta, pero la primera parte de mi respuesta sigue en pie.

Mike Branski
fuente
5

Además de la velocidad, otra diferencia importante es cómo manejan los 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.

Entonces, is_a () resalta posibles errores, mientras que instanceof los suprime.

Csongor Halmai
fuente
2

La optimización es mínima. Y las micro optimizaciones nunca son una buena respuesta, frente a la legibilidad, la comprensión y la estabilidad del código.

(Personalmente prefiero instancia de , pero la elección es suya;))

La principal diferencia es la posibilidad de usar el nombre de clase directo con instanceof

$ una instancia de MyClass

es más corto que

is_a ($ a, MyClass :: class)

(ok ... no es trivial)

La coloración sintáctica entre instanceof (estructura del lenguaje) e is_a también es útil (para mí). dejando el color de la función para operaciones más grandes. Y para un solo uso en if, instancia de dos no necesita más paréntesis.

Nota: Por supuesto, en lugar de MyClass :: class puede usar una cadena directa más corta:

is_a ($ a, 'MyClass')

Pero usar una cadena directa en un código no es una buena práctica .

La colocación sintáctica es mejor y más útil si puede hacer una diferencia entre una cadena simple y nombres de clases. Y es más fácil cambiar nombres con nombre de clase constante. Especialmente si usa el espacio de nombres con alias.

Entonces, ¿por qué usar is_a () ?

Por la misma razón: legibilidad e inteligibilidad. (la elección es suya) Especialmente cuando se usa con ! u otros operadores booleanos: is_a parece más práctico con paréntesis.

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

es más legible que:

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

Otra buena razón es cuando necesita usar la devolución de llamada en las funciones. (como array_map ...) instanceof no es una función, es una construcción de lenguaje, por lo que no puede usarla como devolución de llamada.

En estos casos, is_a puede ser útil

Titsta
fuente
1

No puedo hablar por el rendimiento, todavía no he medido nada, pero dependiendo de lo que esté intentando, existen limitaciones con instanceof . Mira mi pregunta, recientemente, al respecto:

PHP 'instanceof' falla con constante de clase

Terminé usando en su is_alugar. Me gusta la estructura de instanceofmejor (creo que se lee mejor) y continuaré usándola donde pueda.

Nathan Loding
fuente
1

Aquí están los resultados de rendimiento obtenidos de aquí :

instanceof es más rápido.

Las funciones

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

Tiempos (ejecutados 5000 veces cada uno)

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

Hay un escenario donde solo is_a()funciona y instanceoffallará.

instanceof espera un nombre de clase literal o una variable que sea un objeto o una cadena (con el nombre de una clase) como argumento correcto.

Pero si desea proporcionar la cadena de un nombre de clase de una llamada de función, no funcionará y dará como resultado un error de sintaxis.

Sin embargo, el mismo escenario funciona bien con is_a().

Ejemplo:

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

Esto se basa en PHP 7.2.14.

Erik Kalkoken
fuente