如何在PHP中检查一个类是否使用了一个trait?

54
注意,一个特质可能会使用其他特质,所以类可能不直接使用该特质。而且这个类可能是从使用该特质的父类继承而来的。
这是一个可以在几行代码内解决的问题还是我需要循环做些什么?

1
这个页面的注释中有一些函数,它们将返回类(及其父类等)使用的所有特性:http://php.net/manual/en/function.class-uses.php - iainn
@iainn。我认为Ulf的应该可以完成这项工作! - bijiDango
10个回答

48

当然会的。感谢您,也感谢 Laravel 一直以来的支持。 - Elliot

25
class_uses()函数将返回一个包含该类使用的所有特性的名称的数组,传递给它一个类名或实例即可...但是,您需要“递归”遍历继承树以获取使用的所有特性,并遍历每个特性。 编辑 请注意,链接的PHP文档页面的评论部分提供了一个示例函数,展示如何进行递归。

20

在特征列表中检查您的特征:

$usingTrait = in_array(
    MyTrait::class, 
    array_keys((new \ReflectionClass(MyClass::class))->getTraits())
);

如果MyClass使用MyTrait,则返回true或false


7
дЄЇдїАдєИдЄНзЫіжО•дљњзФ®class_usesиАМи¶БдљњзФ®еПНе∞ДеСҐпЉЯ - abdulmanov.ilmir
3
$usingTrait = in_array(MyTrait::class, class_uses(MyClass::class))$这行代码的作用是判断一个名为MyClass的类是否使用了一个叫做MyTrait的特性。如果使用了,$usingTrait的值将会是true,否则为false。 - Philipp Dahse
我检查了一下,这个有着相同的缺陷,就像class_uses一样 - 它们都不能返回父类中定义的特性。 - jave.web

16

如果你想要检查类使用的特质,你可以使用class_uses函数,它将仅返回该类所使用的所有特质的数组。

in_array(SoftDeletes::class, class_uses(Model::class), true) //return boolean

如果你想检查类或其父类是否使用了 trait,请使用class_uses_recursive函数。

in_array(SoftDeletes::class, class_uses_recursive(Model::class), true) //return boolean

15

另一种方法是使用定义您的特性所期望的接口。然后,您可以使用"instanceof SomeInterface"而不是进行反射或鸭子类型。


5

通常,检查你打算使用的API部分是否存在是一个很好的替代方式。
method_exists(mixed $object, string $method_name): bool

此外,如@MeatPopsicle所提到的,Trait经常与(标记)接口结合使用。


4
下面的函数来自于ulf的评论,可以在http://php.net/manual/en/function.class-uses.php找到。非常完美地运行。
function class_uses_deep($class, $autoload = true)
{
    $traits = [];

    // Get traits of all parent classes
    do {
        $traits = array_merge(class_uses($class, $autoload), $traits);
    } while ($class = get_parent_class($class));

    // Get traits of all parent traits
    $traitsToSearch = $traits;
    while (!empty($traitsToSearch)) {
        $newTraits = class_uses(array_pop($traitsToSearch), $autoload);
        $traits = array_merge($newTraits, $traits);
        $traitsToSearch = array_merge($newTraits, $traitsToSearch);
    };

    foreach ($traits as $trait => $same) {
        $traits = array_merge(class_uses($trait, $autoload), $traits);
    }

    return array_unique($traits);
}

1

我在这个主题上遇到了一些问题,写了一个解决方案,想与大家分享。通过使用 new ReflectionClass($objectOrClass),您可以使用实例方法 getTraits()。问题在于它只返回$objectOrClass的特征数组,而不是从特征或扩展类继承的特征。

以下是解决方案:

/** @return ReflectionClass[] */
function get_reflection_class_traits( ReflectionClass $reflection, array $traits = [] ): array {
    if ( $reflection->getParentClass() ) {
        $traits = get_reflection_class_traits( $reflection->getParentClass(), $traits );
    }

    if ( ! empty( $reflection->getTraits() ) ) {
        foreach ( $reflection->getTraits() as $trait_key => $trait ) {
            $traits[$trait_key] = $trait;
            $traits = get_reflection_class_traits( $trait, $traits );
        }
    }

    return $traits;
}

// string|object $objectOrClass Either a string containing the name of the class to reflect, or an object.
$objectOrClass = //...
$reflection = new ReflectionClass( $objectOrClass );
$all_traits = $this->get_reflection_class_traits( reflection );

0

这是我在我的工具类中拥有的内容

static function 
isTrait( $object, $traitName, $autoloader = true )
{
    $ret = class_uses( $object, $autoloader ) ;
    if( is_array( $ret ) )
    {
        $ret = array_search( $traitName, $ret ) !== false ;
    }
    return $ret ;
}

我的眼睛都要流血了,请检查 PSR2。 - Tonoslav

0
使用 :
array_keys((new \ReflectionClass($object))->getTraits()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接