How to check if a class uses a trait in PHP?

Viewed 32348

Notice that a trait may use other traits, so the class may not be using that trait directly. And also the class may be inherited from a parent class who is the one uses the trait.

Is this a question that can be solved within several lines or I would have to do some loops?

9 Answers

Check your trait in a trait list:

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

This return true or false if MyClass uses MyTrait

Another way to approach this is to use interfaces that define what is expected of your traits. Then you are using "instanceof SomeInterface" instead of doing reflection or duck typing.

If you want to check the class only you can use class_uses it will return an array of all traits used by the class only

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

If you want to check if the class or its parents use the trait use class_uses_recursive

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

Often, checking if the part of API you intend to use exists is a good enough substitute.
method_exists ( mixed $object , string $method_name ) : bool

Also, as @MeatPopsicle mentions, traits are often used in combination with (marker-)interfaces.

This is what I have in my Tools class

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

I had some problems with this topic and I wrote a solution that I want to share with every one. By using a new ReflectionClass($objectOrClass), you can use the instance method getTraits(). The problem is it will only returns an array of traits for the $objectOrClass, and not the inherited traits from the traits or from the extended class.

Here is the solution :

/** @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 );
Related