PHP instanceof for traits

前端 未结 4 945
猫巷女王i
猫巷女王i 2020-12-28 13:37

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

相关标签:
4条回答
  • 2020-12-28 14:15

    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.

    0 讨论(0)
  • 2020-12-28 14:18

    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));
    }
    
    0 讨论(0)
  • 2020-12-28 14:21

    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.

    0 讨论(0)
  • 2020-12-28 14:33

    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')){
        ...
    }
    
    0 讨论(0)
提交回复
热议问题