Quelle est la difference entre is_a et instanceof?

205

Je sais que instanceofc'est un opérateur et c'est is_aune méthode.

Les performances de la méthode sont-elles plus lentes? Que préférez-vous utiliser?

Daniel
la source
15
is_a () pourrait être plus lent - mais vous pouvez l'appeler en utilisant call_user_func () alors que instanceof ne peut pas être appelé de cette façon ...
Kamil Tomšík

Réponses:

211

Mettre à jour

Depuis PHP 5.3.9 , la fonctionnalité de is_a()a changé. La réponse d'origine ci-dessous indique que is_a() doit accepter un Objectcomme premier argument, mais les versions PHP> = 5.3.9 acceptent désormais un troisième argument booléen facultatif $allow_string(par défaut false) pour permettre des comparaisons de noms de classe de chaînes à la place:

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 principale différence dans le nouveau comportement entre instanceofet is_a()est qu'il instanceofvérifie toujours que la cible est un objet instancié de la classe spécifiée (y compris les classes d'extension), alors qu'il is_a()ne nécessite que l'objet soit instancié lorsque l' $allow_stringargument est défini sur la valeur par défaut de false.


Original

En fait, is_ac'est une fonction, alors que instanceofc'est une construction de langage. is_asera beaucoup plus lent (car il a tous les frais généraux d'exécution d'un appel de fonction), mais le temps d'exécution global est minimal dans l'une ou l'autre méthode.

Il n'est plus obsolète à partir de la version 5.3, il n'y a donc pas de souci là-bas.

Il y a cependant une différence. is_aêtre une fonction prend un objet comme paramètre 1 et une chaîne (variable, constante ou littérale) comme paramètre 2. Donc:

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

instanceof prend un objet comme paramètre 1 et peut prendre un nom de classe (variable), une instance d'objet (variable) ou un identificateur de classe (nom de classe écrit sans guillemets) comme paramètre 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
la source
36
Pourquoi n'était pas is_aobsolète?
Theodore R. Smith
21
@ theodore-r-smith Selon la documentation, il "n'a pas été déprécié par la demande populaire" php.net/manual/en/migration53.undeprecated.php
Janci
3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell
39
Une autre chose à noter à propos de is_al' instanceofopérateur est qu'il is_aacceptera des expressions pour le deuxième paramètre, tandis que instanceof ne le fera pas. Par exemple, is_a($object, 'Prefix_'.$name)fonctionne tout en $object instanceof 'Prefix_'.$namene pas
Evan Purkhiser
6
is_an'aurait jamais dû être déprécié en premier lieu. Il est un peu tard pour le réparer maintenant. Le problème est que l' instanceofopérateur jette des erreurs de syntaxe dans PHP 4, et depuis qu'il is_aétait obsolète en même temps que l'opérateur a été introduit, il est devenu impossible d'écrire du code pour PHP 4 et 5 sans lancer un E_STRICT. Vous ne pouvez même pas le faire if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }car cela provoquerait toujours une erreur de syntaxe en PHP 4.
meustrus
47

Voici les résultats de performance de is_a () et instanceof :

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

La source du test est ici .

Alexander Yancharuk
la source
6
En d'autres termes, la différence n'est importante que si vous devez enregistrer ~ 0,015 seconde par 10000 utilisations.
CJ Dennis
1
Depuis php 7il n'y a pas de différence.
MAX
@CJDennis Par expérience, quand tout le monde pense comme ça, le produit final sera plus lent que prévu. (Serveurs Soft + OS + non optimisés). N'oubliez pas que le temps ajouté n'est pas toujours linéaire, mais peut être exponentiel. Ayez toujours à l'esprit la performance.
Toto
@Toto Il existe un excellent article de blog sur ce que les développeurs expérimentés peuvent apprendre des débutants. J'espère que vous pourrez le voir en haut à droite. Attention à l'optimisation prématurée! Résolvez les problèmes de synchronisation uniquement lorsqu'ils sont devenus des problèmes ! Si les performances sont acceptables telles quelles, ne passez pas de temps à les changer!
CJ Dennis
10

instanceofpeut être utilisé avec d'autres instances d'objet, le nom de la classe ou une interface. Je ne pense pas que cela is_a()fonctionne avec les interfaces (seulement une chaîne représentant un nom de classe), mais corrigez-moi si c'est le cas. (Mise à jour: voir https://gist.github.com/1455148 )

Exemple 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'

les sorties:

bool(true)
bool(true)
bool(false)
Lotus Notes
la source
3
is_afonctionne avec les interfaces de la même manière que instanceof(j'allais dire la même chose, mais je l'ai vérifié avant de soumettre, et cela fonctionne en effet) ...
ircmaxell
2
-1 veuillez résumer la mise à jour plutôt que de simplement vous lier à un résumé. Cela n'aide pas les gens qui essaient d'apprendre.
Erick Robertson
5

En ce qui concerne la réponse de ChrisF, is_a() n'est plus obsolète depuis PHP 5.3.0. Je trouve qu'il est toujours plus sûr de consulter la source officielle pour des choses comme ça.

En ce qui concerne votre question, Daniel, je ne peux pas dire sur les différences de performances, mais une partie se résumera à la lisibilité et avec laquelle vous trouverez plus facile à travailler.

En outre, il y a une discussion au sujet de la confusion autour de la négation d' un instanceofchèque vs is_a(). Par exemple, instanceofvous feriez:

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

vs ce qui suit pour is_a():

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

ou

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

Modifier On dirait que ChrisF a supprimé sa réponse, mais la première partie de ma réponse est toujours valable.

Mike Branski
la source
5

Outre la vitesse, une autre différence importante réside dans la façon dont ils gèrent les boîtiers de bord.

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.

Ainsi, is_a () met en évidence les bogues possibles tandis que instanceof les supprime.

Csongor Halmai
la source
2

L'optimisation est minime. Et les micro-optimisations ne sont jamais une vraie bonne réponse, devant la lisibilité, l'intelligibilité et la stabilité du code.

(personnellement, je préfère l' instance , mais le choix vous appartient;))

La principale différence est la possibilité d'utiliser un nom de classe direct avec instanceof

$ une instance de MyClass

est plus court que

is_a ($ a, MyClass :: class)

(ok… ce n'est pas anodin.)

La coloration syntaxique entre instanceof (structure du langage) et is_a est également utile (pour moi). laissant la fonction colorer à des opérations plus importantes. Et pour une utilisation unique dans if, instanceof n'a pas besoin de plus de parenthèses.

Remarque: Bien sûr, au lieu de MyClass :: class, vous pouvez utiliser une chaîne directe plus courte:

is_a ($ a, 'MaClasse')

Mais utiliser une chaîne directe dans un code n'est pas une bonne pratique .

La collation syntaxique est meilleure et plus utile si vous pouvez faire la différence entre une chaîne simple et des noms de classes. Et il est plus facile de changer les noms avec un nom de classe constant. Spécialement si vous utilisez un espace de noms avec un alias.

Alors, pourquoi utiliser is_a () ?

Pour la même raison: lisibilité et incompréhension. (à vous de choisir) Spécialement utilisé avec ! ou d'autres opérateurs booléens: is_a semble plus pratique avec des parenthèses.

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

est plus lisible que:

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

Une autre bonne raison est lorsque vous devez utiliser le rappel dans les fonctions. (comme array_map …) instanceof n'est pas une fonction, c'est une construction de langage, vous ne pouvez donc pas l'utiliser comme rappel.

Dans ces cas, is_a peut être utile

Titsta
la source
1

Je ne peux pas parler de performance - je n'ai encore rien mesuré - mais selon ce que vous essayez, il y a des limites avec instanceof . Découvrez ma question, récemment, à ce sujet:

PHP 'instanceof' échoue avec la constante de classe

J'ai fini par utiliser à la is_aplace. J'aime la structure de instanceofmieux (je pense que ça se lit mieux) et je continuerai de l'utiliser quand je le pourrai.

Nathan Loding
la source
1

Voici les résultats de performance obtenus à partir d' ici :

instanceof est plus rapide.

Les fonctions

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

Heures (exécutées 5000 fois chacune)

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

Il existe un scénario où seul is_a()fonctionne et instanceoféchouera.

instanceof attend un nom de classe littéral ou une variable qui est soit un objet soit une chaîne (avec le nom d'une classe) comme argument de droite.

Mais si vous souhaitez fournir la chaîne d'un nom de classe à partir d'un appel de fonction, cela ne fonctionnera pas et entraînera une erreur de syntaxe.

Cependant, le même scénario fonctionne bien avec is_a().

Exemple:

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

Ceci est basé sur PHP 7.2.14.

Erik Kalkoken
la source