Чим відрізняється is_a від instanceof?


205

Я знаю, що instanceofце оператор і цеis_a це метод.

Чи більш повільним є метод? Що б ви хотіли використовувати?


15
is_a () може бути повільнішим - але ви можете викликати це за допомогою call_user_func (), тоді як instanceof не можна назвати таким чином ...
Kamil Tomšík

Відповіді:


211

Оновлення

Станом на PHP 5.3.9 , функціонал компанії is_a()змінився. У початковій відповіді нижче зазначено, що is_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 Відповідно до документації, це " недооцінено
Janci

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

39
Ще одне, що слід зазначити щодо оператора is_avs, instanceofце те, що is_aбуде приймати вирази для другого параметра, в той час як instanceof wont. Наприклад, 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 Dennis

1
Станом на php 7різницю немає.
МАКС,

@CJDennis За досвідом, коли всі думають так, кінцевий продукт буде повільнішим, ніж очікувалося. (Soft + OS + сервери неоптимізовані). Пам'ятайте, що доданий час не завжди є лінійним, але може бути експоненціальним. Завжди майте на увазі виступ.
Тото

@Toto Відмінна публікація в блозі про те, що досвідчені розробники можуть дізнатися у новачків. Сподіваємось, ви побачите це вгорі праворуч. Остерігайтеся передчасної оптимізації! Вирішуйте проблеми з термінами лише після того, як вони стали проблемами ! Якщо вистава прийнятна такою, яка не є, не витрачайте час на її зміну!
CJ Dennis

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) { //... }
?>

Edit Схоже, 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

$ екземпляр MyClass

коротше, ніж

is_a ($ a, MyClass :: клас)

(добре ... це не банально.)

Синтаксичне забарвлення між instanceof (мовна структура) та is_a також корисне (для мене). надаючи функціональний колір більшій операції. І для одноразового використання, якщо, instanceof не потребує більше дужок.

Примітка. Звичайно, замість MyClass :: class ви можете використовувати коротший прямий рядок:

is_a ($ a, "MyClass")

Але використовувати прямий рядок у коді не є хорошою практикою .

Синтаксичне зібрання є кращим і кориснішим, якщо ви можете змінити назви простих рядків і класів. І простіше міняти імена з постійним іменем класу. Спеціально, якщо ви використовуєте простір імен з псевдонімом.

Отож, як використовувати is_a () ?

З тієї ж причини: читабельність та невідчутність. (вибір за вами) Спеціальність при використанні ! або інші булеві оператори: is_a здається більш вдалим з дужками.

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

читабельніше, ніж:

if ($ a AND (! ($ екземпляр MyClass) АБО ($ intance 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.