25

Is there any function in PHP (5.4) to get used traits as array or similar:

class myClass extends movingThings {
  use bikes, tanks;

  __construct() {
    echo 'I\'m using the two traits:' . ????; // bikes, tanks
  }
}
2
  • 1
    I tried to make your question clearer. I think you're wanting to get bikes and tanks (your traits) from within the object or class. Similar to get_class_methods() except get_class_traits() which doesn't exist.
    – Mike B
    Commented Nov 29, 2012 at 19:43
  • 1
    @Nik.... , why did you close it? You should not be using "close everything" approach when using /review.
    – tereško
    Commented Dec 1, 2012 at 18:51

7 Answers 7

36

To easily get the used traits you can call class_uses()

$usedTraits = class_uses(MyClass);
// or
$usedTraits = class_uses($myObject);

General recommendations

When checking for available functionality, I would generally recommend to use interfaces. To add default functionality to an interface you would use traits. This way you can also benefit from type hinting.

Force an object having functionality by implementing an interface and then use a trait to implement default code for that interface.

class MyClass 
    implements SomeInterface 
{
    use SomeTrait;
}

Then you can check the interface by;

$myObject = new MyClass();
if ($myObject instanceof SomeInterface) {
    //...
}

And still use type hinting;

function someFunction( SomeInterface $object )
{ 
    //...
}
0
12

You can write it yourself, by using the ReflectionClass

$rc = new ReflectionClass('myClass');
$count = count($rc->getTraits());
1
  • Does getTraits() work the same as class_uses? Does it return the name of traits, used by class traits? Or traits, used by parent class? Commented Jul 9, 2014 at 15:51
8

Just my 2 cents =)

in_array( "CLASS_NAME", class_uses($model) ) 

Or with PHP > 5.6

in_array( CLASS_NAME::class, class_uses($model) )
2

class-uses(<class>) will get the immediate traits of <class> however it won't get all inherited traits by way of parent classes or traits of traits etc...

If you need to get absolutely all inherited traits on a class I would recommend reading the comments in the official docs here:

http://php.net/manual/en/function.class-uses.php

1
  • @not_jagg_at_adecosystem shows a partial solution to this limitation.
    – Henry
    Commented Oct 29, 2015 at 23:59
2

class_uses and ReflectionClass->getTraits will not work if you want to get traits from child class.

Example.

trait A {}

class Mother {
    use A;
}

class Child extends Mother {}

var_dump(class_uses('Child'));  // empty array
var_dump(class_uses('Mother')); // has A

I have this problem so I write simple code for get all traits from classes.

function all_class_uses($model)
{
    $class = new ReflectionClass($model);
    $traits = $class->getTraits();
    while($parent = $class->getParentClass()) {
        $traits += $class->getTraits();
        $class = $parent;
    }
    return array_combine(array_keys($traits), array_keys($traits));
}
1
  • I think $traits += $class->getTraits(); in while loop should be $traits += $parent->getTraits(); Commented Apr 18, 2018 at 6:35
1

I wish that will be useful (thanks to Maurice for interface usage):

    interface IHaveHasTrait
    {
        public function has_trait($name);
    };

    trait THaveHasTrait
    {
        public function has_trait($name)
        {
            $classes = class_parents( $this );
            $classes[] = get_class( $this );
            foreach( $classes as $class ) {
                foreach( class_uses( $class ) as $t ) {
                    if( $t === $name ) {
                        return true;
                    }
                }
            }
            return false;
        }
    };

    trait TLinkedListItem
    {
        use THaveHasTrait;
        public $next;
        public $prev;
    };

    class A implements IHaveHasTrait
    {
        use TLinkedListItem;
        public $text;

        public function __construct( $_text )
        {
            $this->text = $_text;
        }
    };

    class B extends A{};

    class C extends B{};

    class LinkedList
    {
        public function insertItem( &$item, $position=0, $relative=false )
        {
            if( is_a( $item, 'IHaveHasTrait' ) ) {
                echo $item->has_trait( 'TLinkedListItem' ) ? 'has' : 'not';
            }
        }
    };

    $a = new C('a');
    $l = new LinkedList;
    $l->insertItem($a);
    ?>
-2

Short answer: you shouldn't. Traits are almost exactly copy and paste code. You don't NEED to know which traits are used, only on what the traits generate.

Answer I don't want to give: use ReflectionClass::getTraits. I'm not going to elaborate on this one.

9
  • Point of clarification: Are you saying you shouldn't use traits at all or shouldn't develop functionality that depends on what traits are implemented?
    – Mike B
    Commented Nov 29, 2012 at 19:47
  • Traits are not just copy&paste. Why not use an information about traits like some kind of Metadata?
    – Ziumin
    Commented Nov 29, 2012 at 19:49
  • Imho traits should almost always be avoided, because it is just another way of tight coupling code.
    – PeeHaa
    Commented Nov 29, 2012 at 19:49
  • @Ziumin In PHP they are almost copy and paste. I chose my wording carefully. Commented Nov 29, 2012 at 19:53
  • @Levi Morrison I didn't say you that your answer is wrong. What about my second question?
    – Ziumin
    Commented Nov 29, 2012 at 19:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.