How to check if a class uses a trait in PHP?
Asked Answered
E

10

64

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?

Eleonoreeleoptene answered 14/9, 2017 at 11:33 Comment(2)
There are some functions that will return all traits used by a class (and its parents/etc) in the comments on this page: php.net/manual/en/function.class-uses.phpMutualize
@iainn. I think ulf's shall do the work!Eleonoreeleoptene
O
55

If anyone has this problem while using the Laravel framework, that has a helper function called class_uses_recursive().

https://laravel.com/docs/8.x/helpers#method-class-uses-recursive

So you can do something like this:

in_array(SomeTrait::class, class_uses_recursive(SomeClass::class))
Otherdirected answered 15/9, 2020 at 12:51 Comment(1)
Of course it does. Thanks for this, and thanks to Laravel for always having our backs.Shiner
L
26

The class_uses() function will return an array containing the names of all traits used by that class, and will work by passing it a class name or an instance.... however, you'd need to "recurse" through the inheritance tree to get all traits used, and through each trait as well

EDIT

Note that stealz at op dot pl has provided an example function showing how to do this recursion in the comments section of the linked PHP Docs page

Lardner answered 14/9, 2017 at 11:34 Comment(0)
T
23

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

Tyishatyke answered 26/9, 2018 at 19:5 Comment(2)
why not just class_uses instead of reflection?Aneurysm
I checked and this has the same flaw as class_uses - they both don't return traits defined in parents.Propylaeum
S
20

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.

Sungsungari answered 20/2, 2019 at 15:42 Comment(0)
L
20

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
Launcher answered 6/2, 2021 at 1:26 Comment(0)
Z
6

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.

Zaccaria answered 29/4, 2019 at 0:30 Comment(0)
E
5

The below function is from http://php.net/manual/en/function.class-uses.php, ulf's comment. Works perfect.

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);
}
Eleonoreeleoptene answered 14/9, 2017 at 11:51 Comment(0)
V
1

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 );
Vote answered 16/1, 2022 at 2:30 Comment(0)
E
0

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 ;
}
Exurbia answered 7/1, 2020 at 18:38 Comment(1)
My eyes bleed, please check PSR2Speaker
P
0

Using ReflactionClass :

array_keys((new \ReflectionClass($object))->getTraits()
Phototaxis answered 14/8, 2023 at 13:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.