我知道instanceof是一个操作符,is_a是一个方法。

该方法的性能是否较慢?你更喜欢用什么?


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)

更新

从PHP 5.3.9开始,is_a()的功能发生了变化。下面的原始答案指出,is_a()必须接受一个对象作为第一个参数,但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

我不能谈论性能——我还没有测量过任何东西——但根据您的尝试,instanceof有局限性。看看我最近提出的问题:

PHP 'instanceof'类常量失败

我最终使用了is_a。我更喜欢instanceof的结构(我认为它读起来更好),并将继续在我可以使用的地方使用它。


关于ChrisF的回答,is_a()从PHP 5.3.0起不再弃用。我发现这种事还是听官方消息比较安全。

关于你的问题,丹尼尔,我不能说性能上的差异,但部分原因在于可读性,以及你觉得哪个更容易使用。

此外,还有一些关于否定instanceof check与is_a()的混淆的讨论。例如,instanceof你会这样做:

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

Vs is_a():

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

or

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

看起来ChrisF删除了他的答案,但我的答案的第一部分仍然有效。


下面是is_a()和instanceof的性能结果:

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

测试源在这里。


下面是从中获得的性能结果:

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)

优化是最小的。在代码的可读性、可理解性和稳定性面前,微优化从来都不是一个真正的好答案。

(个人而言,我更喜欢instanceof,但选择是你的;))

主要的区别是可以使用instanceof的直接类名

$一个MyClass实例

短于

is_a($a, MyClass::class)

(好吧,这不是小事。)

instanceof(语言结构)和is_a之间的语法颜色也很有用(对我来说)。让函数为更大的运算上色。 如果在if中单独使用,instanceof不需要更多的括号。

注意: 当然,你可以使用更短的直接字符串来代替MyClass::class:

is_a ($ a,“MyClass”)

但是在代码中使用直接字符串并不是一个好的实践。

如果可以区分简单字符串和类名,那么语法排序会更好,也更有用。 使用常量classname更容易更改名称。如果使用带有别名的命名空间,则具有特殊性。

那么,wy使用is_a() ?

出于同样的原因:可读性和不可理解性。(选择权在你) 与!或者其他布尔运算符:is_a用圆括号似乎更实用。

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

比:

if($a AND (!($a instanceof MyClass)或($a instanceof MyOtherClass))

另一个很好的理由是当你需要在函数中使用回调时。(像array_map…) Instanceof不是一个函数,它是一个语言结构,所以你不能把它用作回调。

在这种情况下,is_a可能很有用


除了速度,另一个重要的区别是如何处理边缘情况。

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抑制它们。


有一种情况是,只有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的。


关于is_a()有一件有趣的事情需要注意:如果你正在为你的类使用自动加载器、名称空间和别名,你将需要在is_a()上使用你的类的真实和全名,因为这个方法不能很好地理解你的上下文中的什么是什么。另一方面,Instanceof理解它。

例如(不是双关语):

<?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
    }
}