PHP instanceof操作员提示

PHP中的instanceof运算符非常适合确保在对对象进行操作之前先查看它的类型。虽然可以直接使用,但是使用它可能会导致一些不良的副作用。

作为一个基本示例,让我们创建几个接口和类来展示操作中的instanceof运算符。我使用的是您可能会在系统中找到的对象名称,而不仅仅是使用一些测试名称。它由可能构成商务系统一部分的用户和订单组成。

interface UserInterface {}

class User implements UserInterface {}

 

interface OrderInterface {}

class Order implements OrderInterface {}

如果我们实例化User对象,我们可以检测到该用户是否是User类的实例,如下所示。

$user = new User();

var_dump($user instanceof User); // 返回true

当User对象实现接口时,我们还可以检测User对象是否是此类接口的实例。

var_dump($user instanceof UserInterface); // 返回true

相反,如果我们要查看创建的$user变量是否是另一种对象的实例,则它将返回false,如下所示。

var_dump($user instanceof Order); // returns false

如果不确定要接收哪种接口或对象,则可以传入一个包含接口名称的变量。

$interface = 'UserInterface';

var_dump($user instanceof $interface);

请注意,如下面的代码片段所示,仅以字符串形式传递接口会产生语法错误。用于检测对象或接口类型的项目必须是变量或完全限定的类或接口名称。

var_dump($user instanceof 'UserInterface');

// PHP Parse error: syntax error, unexpected ''UserInterface'' (T_CONSTANT_ENCAPSED_STRING) inindex.phpon line 2

否定operator的实例要简单一些,但是可以通过在语句的开头加上一个感叹号来实现。

var_dump(!$user instanceof UserInterface); // returns false

通常最好将整个内容包装在方括号中,以便您可以确定检查的结果。

var_dump(!($user instanceof UserInterface)); // returns false

您还可以将instanceof运算符的输出与false进行比较,这实际上会将其取反。尽管您可能会认为可能会错过感叹号,但我觉得这很难理解。

var_dump(FALSE === $user instanceof UserInterface); // returns false

当涉及名称空间时,必须注意使用正确的语法。使用完全限定的名称空间时,必须使用斜杠,否则将找不到正确的实例。最好的做法是完全不使用完全限定的名称空间,而仅依赖于您要查找的接口名称。下面的示例正在研究一种名为FormStateInterface的Drupal接口,它使用三种不同的方式来记录类名。

use Drupal\Core\Form\FormStateInterface;

 

var_dump($form_state instanceof Drupal\Core\Form\FormStateInterface); // returns false

var_dump($form_state instanceof \Drupal\Core\Form\FormStateInterface); // 返回true

var_dump($form_state instanceof FormStateInterface); // 返回true

单个instanceof检查很容易理解,但是如果您尝试检测某个对象是否是一系列对象类型之一,则代码将变得有点难以阅读。例如,假设您正在尝试检测对象是否是帖子开头定义的三种类型的接口之一;您可以创建如下的if语句。

var_dump($object instanceof UserInterface || $object instanceof ProductInterface || $object instanceof OrderInterface); // 返回true

返回true,表示该对象是我们正在寻找的实例类型之一。

我找到了一个很好的函数,可以在读取前一天堆栈溢出的同时将其整齐地封装起来(请参阅此处的原始堆栈溢出注释)。要检测对象是否为一系列类型之一,可以使用以下函数,该函数将接收一个对象和一个类名数组。

function isInstanceOf($object, Array $classnames) {

    foreach($classnames as $classname) {

        if($object instanceof $classname){

            return true;

        }

    }

    return false;

}

可以通过以下方式运行。传递先前创建的用户对象和包含我们要作为字符串查找的实例类型的数组,将返回true。

var_dump(isInstanceOf($user, ['UserInterface', 'ProductInterface', 'OrderInterface'])); // 返回true

instanceof运算符还将对子对象起作用。使用下面的代码创建一个接口,定义一个User类,然后定义一个扩展User类的Administrator类。

interface UserInterface {}

class User implements UserInterface {}

class Administrator extends User {}

我们可以实例化User和Administrator对象,并尝试以不同的方式检测它们。 

$user = new User();

$administrator = new Administrator();

 

var_dump($user instanceof UserInterface); // 返回true

var_dump($user instanceof User); // 返回true

var_dump($user instanceof Administrator); // returns false

 

var_dump($administrator instanceof UserInterface); // 返回true

var_dump($administrator instanceof User); // 返回true

var_dump($administrator instanceof Administrator); // 返回true

上面的代码要注意的是,User对象不是Administrator对象的实例,因此比较返回false。但是,Administrator对象是User对象的实例,因此比较是正确的。

如果我们试图检测到仅管理员对象而不是用户对象的实例,那么会发生什么。不幸的是,此处不能使用instanceof运算符。取而代之的是,为了检测只是一种类型的类的您正在寻找你需要使用用一个不同的比较get_class()PHP方法。

var_dump(get_class($administrator) === 'Administrator'); // 返回true

var_dump(get_class($user) === 'Administrator'); // returns false

请注意,User对象不是Administrator对象,因此比较返回false。上面的内容也可以使用:: class magic常量以不同的方式编写,以返回类名称的字符串。实际上,这就是我通常打印出类名的方式以及编写这种类型的比较的方式。

var_dump(get_class($administrator) === Administrator::class); // 返回true

var_dump(get_class($user) === Administrator::class); // returns false

最终,instanceof运算符很有用,但是您需要遵循以下规则以充分利用它。

  • 当检测对象的类型时,请尝试尽可能地检测实例而不是类。这允许遵循良好的SOLID原则。

  • 不要使用接口的标准名称。仅使用接口名称就足够了,并且遵循最佳实践。

  • 如果要查找实例,请确保将比较结果括在方括号中,以免周围运算符的优先级出现任何不一致之处。

  • 使用继承时要小心,所有继承父类的对象都将被检测为与父类具有相同的类型。

以上是 PHP instanceof操作员提示 的全部内容, 来源链接: utcz.com/z/317525.html

回到顶部