PHP instanceof for traits

自古美人都是妖i 提交于 2019-11-29 00:08:22

问题


What is the proper way to check if a class uses a certain trait?


回答1:


While nothing stops you from using instanceof with traits, the recommended approach is to pair traits with interfaces. So you'd have:

class Foo implements MyInterface
{
    use MyTrait;
}

Where MyTrait is an implementation of MyInterface. Then you check for the interface instead of traits like so:

if ($foo instanceof MyInterface) {
    ...
}

And you can also type hint, which you can't with traits:

function bar(MyInterface $foo) {
    ...
}

In case you absolutely need to know whether a class is using a certain trait or implementation, you can just add another method to the interface, which returns a different value based on the implementation.




回答2:


You can use class_uses function to get an array of all the traits used by a class.

Then you check if this array has a key with the same name of the trait you're testing for.

if so, then your class is using your trait. If not, then it's not using it.




回答3:


It's not really clean and may not be the right solution for your case. But an alternative is to check if the object or class implements a method of the Trait (as usually you don't overwrite existing methods with Trait)

if (method_exists($my_object, 'MyTraitSpecificMethod')){
    ...
}



回答4:


I just found how Laravel solves this and thought I'd share it here. It uses class_uses beneath but goes through all the parents to find all the traits recursively.

It defines a helper function called 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;
}

And you can use it like this:

in_array(MyTrait::class, class_uses_recursive($class));

You can see how they use it to check if a model implements the SoftDeletes trait here:

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


来源:https://stackoverflow.com/questions/36515677/php-instanceof-for-traits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!