开发者

What is the difference between is_a and instanceof?

开发者 https://www.devze.com 2023-01-03 05:32 出处:网络
I am aware that 开发者_运维百科instanceof is an operator and that is_a is a method. Is the method slower in performance? What would you prefer to use?Update

I am aware that 开发者_运维百科instanceof is an operator and that is_a is a method.

Is the method slower in performance? What would you prefer to use?


Update

As of PHP 5.3.9, the functionality of is_a() has changed. The original answer below states that is_a() must accept an Object as the first argument, but PHP versions >= 5.3.9 now accept an optional third boolean argument $allow_string (defaults to false) to allow comparisons of string class names instead:

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

The key difference in the new behavior between instanceof and is_a() is that instanceof will always check that the target is an instantiated object of the specified class (including extending classes), whereas is_a() only requires that the object be instantiated when the $allow_string argument is set to the default value of false.


Original

Actually, is_a is a function, whereas instanceof is a language construct. is_a will be significantly slower (since it has all the overhead of executing a function call), but the overall execution time is minimal in either method.

It's no longer deprecated as of 5.3, so there's no worry there.

There is one difference however. is_a being a function takes an object as parameter 1, and a string (variable, constant, or literal) as parameter 2. So:

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

instanceof takes an object as parameter 1, and can take a class name (variable), object instance (variable), or class identifier (class name written without quotes) as parameter 2.

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


Here is performance results of is_a() and instanceof:

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

Test source is here.


instanceof can be used with other object instances, the class's name, or an interface. I don't think that is_a() works with interfaces (only a string representing a class name), but correct me if it does. (Update: See https://gist.github.com/1455148)

Example from 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'

outputs:

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


There is a scenario where only is_a() works and instanceof will fail.

instanceof expects a literal class name or a variable that is either an object or a string (with the name of a class) as its right argument.

But if you want to provide the string of a class name from a function call it will not work and result in a syntax error.

However, the same scenario works fine with is_a().

Example:

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

This is based on PHP 7.2.14.


In regards to ChrisF's answer, is_a() is no longer deprecated as of PHP 5.3.0. I find it's always safer to go by the official source for things like this.

With regards to your question, Daniel, I can't say about the performance differences, but part of it will come down to readibility and which you find easier to work with.

Also, there is some discussion about the confusion around negating an instanceof check vs is_a(). For example, for instanceof you would do:

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

vs the following for is_a():

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

or

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

Edit Looks like ChrisF deleted his answer, but the first part of my answer still stands.


Besides the speed, another important difference is how they handle edge cases.

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.

So, is_a() highlights possible bugs while instanceof suppresses them.


The optimisation is minimal. And micro-optimisations are never a real good answer, in front of the readability, understandability and stability of the code.

( personaly I prefere instanceof, but the choice is yours ;) )

The principal difference is the possibility to use direct class name with instanceof

$a instanceof MyClass

is shorter than

is_a($a, MyClass::class)

( ok… it’s not trivial. )

The syntaxical coloration between instanceof (language structure) and is_a is usefull too (for me). letting function color to bigger operations. And for single use in if, instanceof dosn’t need more parenthesis.

Note : Of course instead of MyClass::class you can use a shorter direct string :

is_a($a,'MyClass')

But use direct string in a code isn’t a good practice.

The syntaxical colloration is better and more usefull if you can make a difference between simple string and classes names. And it's easier to change names with constant classname. Specialy if you use namespace with alias.

So, wy use is_a() ?

For same raison : readability and undestandability. (the choice is yours) Specialy when used with ! or others boolean operators : is_a seems more pratical with parenthesis.

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

is more readable than :

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

An other good reason is when you need use callback in functions. ( like array_map … ) instanceof isn’t a function, it’s a language construct, so you cannot use it as callback.

In thoses cases, is_a may be usefull


I can't speak for performance -- I haven't measured anything yet -- but depending on what you are attempting, there are limitations with instanceof. Check out my question, just recently, about it:

PHP 'instanceof' failing with class constant

I've ended up using is_a instead. I like the structure of instanceof better (I think it reads nicer) and will continue to use it where I can.


Here are performance results obtained from here:

instanceof is faster.

Functions

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

Times (run 5000 times each)

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


One interesting thing to note about is_a(): If you're using autoloader, namespaces and aliases for your classes, you'll need to use the true and full name of your class on is_a() because the method will not understand quite well what is what on your context. instanceof, on the other hand, understands it.

For instance (no pun intended):

<?php
namespace MyNamespace;

use \MyNamespace\User;
use \MyNamespace\Thing as Something;

class Test
{
    public function doTest()
    {
        $user = new User();
        var_dump(is_a($user, "User")); // false
        var_dump(is_a($user, "\MyNamespace\User")); // true
        var_dump($user instanceof User); // true
        var_dump($user instanceof \MyNamespace\User); // true
    }

    public function doAnotherTest()
    {
        $something = new Something();
        var_dump(is_a($something, "Something")); // false
        var_dump(is_a($something, "\MyNamespace\Thing")); // true
        var_dump($something instanceof Thing); // true
        var_dump($something instanceof \MyNamespace\Thing); // true
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消