В чем разница между is_a и instanceof?


205

Я знаю, что instanceofэто оператор, а is_aэто метод.

Является ли метод медленнее в производительности? Что бы вы предпочли использовать?


15
is_a () может быть медленнее - но вы можете вызвать его с помощью call_user_func (), тогда как instanceof не может быть вызван таким образом ...
Камиль Томшик

Ответы:


211

Обновить

Начиная с PHP 5.3.9 , функциональность is_a()изменилась. Исходный ответ ниже гласит, что в качестве первого аргумента is_a() необходимо принять a Object, но версии PHP> = 5.3.9 теперь принимают необязательный третий логический аргумент $allow_string(по умолчанию false), чтобы разрешить сравнение имен строковых классов:

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

Основное различие в новом поведении между instanceofи is_a()заключается в том, что instanceofон всегда будет проверять, является ли цель экземпляром объекта указанного класса (включая расширяемые классы), тогда как is_a()требуется только создание экземпляра объекта, когда для $allow_stringаргумента установлено значение по умолчанию - false.


оригинал

На самом деле, is_aэто функция, тогда instanceofкак это языковая конструкция. is_aбудет значительно медленнее (так как все накладные расходы выполняются при вызове функции), но общее время выполнения минимально в обоих методах.

Начиная с версии 5.3 он больше не считается устаревшим, поэтому здесь не о чем беспокоиться.

Однако есть одно отличие. is_aфункция является объектом объекта 1, а строка (переменная, константа или литерал) - параметром 2. Итак:

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

instanceof принимает объект в качестве параметра 1 и может принимать имя класса (переменная), экземпляр объекта (переменная) или идентификатор класса (имя класса записывается без кавычек) в качестве параметра 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class

36
Почему был is_aнедооценен?
Теодор Р. Смит

21
@ theodore-r-smith В соответствии с документацией, это "было недооценено популярным запросом" php.net/manual/en/migration53.undeprecated.php
Янси

3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell

39
Еще одна вещь , чтобы отметить о is_aВ.С. instanceofоператор , который is_aпринимает выражения для второго параметра, в то время как InstanceOf привычка. Например, is_a($object, 'Prefix_'.$name)работает, а $object instanceof 'Prefix_'.$nameне
Эван Пурхизер

6
is_aникогда не должен был быть осужден в первую очередь. Сейчас немного поздно это исправить. Проблема заключается в том, что instanceofоператор генерирует синтаксические ошибки в PHP 4, и, поскольку он is_aбыл объявлен устаревшим в то же время, когда был введен оператор, стало невозможно писать код для PHP 4 и 5 без использования E_STRICT. Вы даже не можете сделать это, if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }потому что это все равно вызовет синтаксическую ошибку в PHP 4.
meustrus

47

Вот результаты производительности is_a () и instanceof :

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

Источник теста здесь .


6
Другими словами, разница важна только в том случае, если вам нужно сэкономить ~ 0,015 секунды на 10000 использований.
CJ Деннис

1
По состоянию на php 7нет никакой разницы.
MAX

@CJDennis По опыту, когда все так думают, конечный продукт будет медленнее, чем ожидалось. (Софт + ОС + серверы неоптимизированы). Помните, что добавленное время не всегда линейно, но может быть экспоненциальным. Всегда имейте в виду производительность.
Тото

@Toto Есть отличный пост в блоге о том, что опытные разработчики могут узнать у начинающих. Надеюсь, вы можете увидеть это в правом верхнем углу. Остерегайтесь преждевременной оптимизации! Решайте проблемы времени только после того, как они стали проблемами ! Если производительность приемлема, не тратьте время на ее изменение!
CJ Деннис

10

instanceofможет использоваться с другими экземплярами объекта, именем класса или интерфейсом. Я не думаю, что это is_a()работает с интерфейсами (только строка, представляющая имя класса), но поправьте меня, если это так. (Обновление: см. Https://gist.github.com/1455148 )

Пример с 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'

выходы:

bool(true)
bool(true)
bool(false)

3
is_aработает с интерфейсами так же, как instanceof(я собирался сказать то же самое, но я проверял это перед отправкой, и это действительно работает) ...
ircmaxell

2
-1 Пожалуйста, подведите итог обновления, а не просто ссылку на суть. Это бесполезно для людей, пытающихся учиться.
Эрик Робертсон

5

Что касается ответа ChrisF, is_a() больше не считается устаревшим с PHP 5.3.0. Я считаю, что для таких вещей всегда безопаснее обращаться к официальному источнику.

Что касается вашего вопроса, Дэниел, я не могу сказать о различиях в производительности, но отчасти это сводится к удобочитаемости, с которой вам легче работать.

Кроме того, есть некоторая дискуссия о путанице вокруг отрицания instanceofпроверки против is_a(). Например, для instanceofвас сделали бы:

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

против следующего для is_a():

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

или

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

Редактировать Похоже, что ChrisF удалил свой ответ, но первая часть моего ответа остается в силе.


5

Помимо скорости, еще одним важным отличием является то, как они обрабатывают крайние случаи.

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.

Итак, is_a () выделяет возможные ошибки, а instanceof их подавляет.


2

Оптимизация минимальна. И микрооптимизация никогда не будет действительно хорошим ответом перед читабельностью, понятностью и стабильностью кода.

(лично я предпочитаю instanceof , но выбор за вами;))

Принципиальным отличием является возможность использования прямого имени класса с instanceof

$ a экземпляра MyClass

короче чем

is_a ($ a, MyClass :: class)

(хорошо ... это не тривиально.)

Синтаксическая окраска между instanceof (структура языка) и is_a также полезна (для меня). позволяя функции цвета для больших операций. И для однократного использования в случае, если экземпляр не нуждается в дополнительных скобках.

Примечание. Конечно, вместо MyClass :: class вы можете использовать более короткую прямую строку:

is_a ($ а, 'MyClass')

Но использование прямой строки в коде не очень хорошая практика .

Синтаксическая раскраска лучше и полезнее, если вы можете различать простые имена строк и классов. И легче поменять имена с постоянным именем класса. Специально, если вы используете пространство имен с псевдонимом.

Так зачем использовать is_a () ?

Для того же смысла: читабельность и непонятность. (выбор за вами) Специально при использовании с ! или другие логические операторы: is_a кажется более практичным с круглыми скобками.

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

более читабельно, чем:

if ($ a AND (! ($ a экземпляра MyClass) ИЛИ ($ a intance of MyOtherClass)))

Другая хорошая причина - когда вам нужно использовать обратный вызов в функциях. (например, array_map …) instanceof - это не функция, это языковая конструкция, поэтому вы не можете использовать ее в качестве обратного вызова.

В этих случаях is_a может быть полезным


1

Я не могу говорить о производительности - я еще ничего не измерил - но в зависимости от того, что вы пытаетесь, есть ограничения instanceof. Проверьте мой вопрос, только недавно, об этом:

PHP 'instanceof' не работает с константой класса

Я закончил тем, что использовал is_aвместо этого. Мне нравится структура instanceofлучше (я думаю, что она читается лучше) и буду продолжать использовать ее, где я могу.


1

Вот результаты производительности, полученные здесь :

instanceof быстрее.

функции

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

Раз (запустить 5000 раз каждый)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)

1

Есть сценарий, где только is_a()работает и не instanceofполучится.

instanceof ожидает буквальное имя класса или переменную, которая является либо объектом, либо строкой (с именем класса) в качестве правильного аргумента.

Но если вы хотите предоставить строку имени класса из вызова функции, это не сработает и приведет к синтаксической ошибке.

Тем не менее, тот же сценарий отлично работает is_a().

Пример:

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

Это основано на PHP 7.2.14.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.