用于特征的PHP instanceof

xpe*_*arx 24 php class instanceof traits

检查某个班级是否使用某种特质的正确方法是什么?

Kub*_*cki 32

虽然没有什么能阻止您使用instanceof特征,但推荐的方法是将特征与接口配对.所以你有:

class Foo implements MyInterface
{
    use MyTrait;
}
Run Code Online (Sandbox Code Playgroud)

在哪里MyTrait实施MyInterface.然后你检查界面而不是像这样的特征:

if ($foo instanceof MyInterface) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

你也可以输入提示,你不能用特征:

function bar(MyInterface $foo) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果您绝对需要知道某个类是使用某个特征还是实现,您只需向该接口添加另一个方法,该方法将根据实现返回不同的值.

  • 这个答案有两种错误。第一:它没有回答最初的问题,即如何检查对象中使用的特征。`class_uses`可以解决问题。但是,说为特征创建冗余接口是“推荐方法”,这是错误的。实际上,这会引起错误倾向,因为当您忘记同时定义接口和特性时,它可能会发生意外的行为。另一方面,您不需要灵活地分别定义接口和特征。因此,保持简单! (4认同)
  • 在非公共逻辑实现的情况下,此方法无用.例如,当您需要使用easy使用BehaviorATrait时,需要生成不同的行为变体; 使用BehaviorBTrait;`它应该基于一些受保护的方法接口.当然,这不是一个好的设计,而是一个工具灵活性的讨论. (2认同)
  • 问题是关于特征,它不能实现接口.以上代码段仅适用于课程. (2认同)
  • 关于此答案还有其他问题:“虽然没有什么阻止您使用带特征的instanceof”使用带特征的instanceof *不起作用*。特质MyTrait {...}类MyClass {use MyTrait; ...} $ myObject = new MyClass(); if(!$ myObject instanceof MyTrait){echo“不起作用”,PHP_EOL; } == >>这将输出“不起作用”! (2认同)
  • 恕我直言,@Armin 的评论也有问题。根据设计,接口_总是_“冗余”。然而,如果应用正确,它们不会增加出错的可能性,反而会减轻出错的可能性,因为开发人员可以将有关预期对象类型的信息保留在一个位置,同时对各种实现细节保持开放。 (2认同)

Rod*_*ias 28

您可以使用class_uses函数来获取类所使用的所有特征的数组.

然后检查此数组是否具有与您正在测试的特征名称相同的密钥.

如果是这样,那么你的班级正在使用你的特质.如果没有,那么就没有使用它.

  • 注意:class_uses 只告诉你这个类是否直接实现了 trait,而不是通过继承。检查 php.net 上的评论,了解有关滚动自己的方法的一些想法,这些方法也遵循类的祖先 http://php.net/manual/en/function.class-uses.php (3认同)

the*_*ton 8

它不是很干净,可能不适合您的情况.但另一种方法是检查对象或类是否实现了Trait的方法(通常不会使用Trait覆盖现有方法)

if (method_exists($my_object, 'MyTraitSpecificMethod')){
    ...
}
Run Code Online (Sandbox Code Playgroud)


sol*_*arc 7

我刚刚发现 Laravel 如何解决这个问题,并想在这里分享。它使用class_usesunder ,但遍历所有父级以递归地找到所有特征。

它定义了一个名为class_uses_recursive的辅助函数:

function class_uses_recursive($class)
{
    if (is_object($class)) {
        $class = get_class($class);
    }

    $results = [];

    foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) {
        $results += trait_uses_recursive($class);
    }

    return array_unique($results);
}

function trait_uses_recursive($trait)
{
    $traits = class_uses($trait);

    foreach ($traits as $trait) {
        $traits += trait_uses_recursive($trait);
    }

    return $traits;
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

in_array(MyTrait::class, class_uses_recursive($class));
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看他们如何使用它来检查模型是否实现 SoftDeletes 特征:

public function throughParentSoftDeletes()
{
    return in_array(SoftDeletes::class, class_uses_recursive($this->throughParent));
}
Run Code Online (Sandbox Code Playgroud)