问题
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