Good Morning Internals,
I am aware that traits in general are a topic where people can have
strong opinions, so I wanted to get an idea of initial thoughts on
this before deciding if it is worth looking into any further.
At the moment, there are three functions in SPL that allow access to
what a given class is using in some way:
-
class_implements -
class_parents -
class_uses(returns the traits the current class uses)
class_uses is unique out of the three in that it only returns traits
declared on the current class as opposed to the parent class (and
higher in inheritance). While this is documented in the manual,
looking at the original bug ticket that introduced class_uses
(https://bugs.php.net/bug.php?id=55266) then it isn't documented why
it only returns traits on the current class. As far as I can tell from
the bug ticket and the code, class_implements was copied for
class_uses and while _zend_class_entry->interaces contains all
interfaces (including from the parent classes),
_zend_class_entry->interaces->trait_names does not.
So, in terms of my question; what would be the general thoughts on a
new optional argument to class_uses that iterates to each parent
class, adding the traits from the parent as well?
Thanks,
Robert
Le 25 mars 2026 à 08:37, Robert Humphries contact@developer-rob.co.uk a écrit :
it isn't documented why it only returns traits on the current class
The reason is given here: https://bugs.php.net/bug.php?id=61554#1333085728 :
Traits are outside the inheritance system: the
parent class is effectively defined by the composition of its own
methods/properties and any traits it uses, so trait usage is not actually
inherited. Furthermore, it doesn't really make sense to reflect trait usage down
the class hierarchy because the same trait may be used more than once within a
class hierarchy.
—Claude
it isn't documented why it only returns traits on the current class
The reason is given here: https://bugs.php.net/bug.php?id=61554#1333085728 :
Traits are outside the inheritance system: the
parent class is effectively defined by the composition of its own
methods/properties and any traits it uses, so trait usage is not actually
inherited. Furthermore, it doesn't really make sense to reflect trait usage down
the class hierarchy because the same trait may be used more than once within a
class hierarchy.
Thanks Claude, that is useful to note, when I initially looked, I was
looking for class_uses in particular as opposed to getTraits from
Reflection.
I am not sure I agree with the reasoning though. If you are using
class_uses in the first place to check for a trait's presence, then
I can't find any difference in use cases for if a trait is defined at
the current level or parent level. Although the trait is not
inherited, the effect of the trait is.
(While you might get differences in behaviour if using multiple traits
and specifying insteadof to resolve conflicts, what functions from
the trait that were used/not used are not provided by class_uses, so
the same trait being used more than once doesn't affect any changes to
the function other than needing to dedupe the list)
~ Robert
Good Morning Internals,
I am aware that traits in general are a topic where people can have
strong opinions, so I wanted to get an idea of initial thoughts on
this before deciding if it is worth looking into any further.At the moment, there are three functions in SPL that allow access to
what a given class is using in some way:
class_implementsclass_parentsclass_uses(returns the traits the current class uses)
class_usesis unique out of the three in that it only returns traits
declared on the current class as opposed to the parent class (and
higher in inheritance). While this is documented in the manual,
looking at the original bug ticket that introducedclass_uses
(https://bugs.php.net/bug.php?id=55266) then it isn't documented why
it only returns traits on the current class. As far as I can tell from
the bug ticket and the code,class_implementswas copied for
class_usesand while_zend_class_entry->interacescontains all
interfaces (including from the parent classes),
_zend_class_entry->interaces->trait_namesdoes not.So, in terms of my question; what would be the general thoughts on a
new optional argument toclass_usesthat iterates to each parent
class, adding the traits from the parent as well?
Frankly I don't like the existence of these 3 functions in SPL.
This is very much in Reflection territory, and it should only ever be in Reflection.
SPL is already a mess of badly designed "features" trying to cohabitate.
The Reflection extension is designed to give you access to do introspection with a well-defined API.
But more over I don't even think you addition makes that much sense.
Traits are not part of the inheritance hierarchy, that's because the "composition" of traits is effectively just copy and paste.
Interfaces are fully inherited onto any child class, so there is no need to iterate through the parents to gather all interfaces.
Traits do not work this way, any "prior" use information is not transmitted due to the copy and paste nature of them.
The current API doesn't even tell you if used traits also use other traits.
I don't even know how it handles trait aliases, or if it even cares about them.
And that's not even going through overridden trait methods/props/constants at any stage of the inheritance chain.
So I'm very much not convinced about this, nor do I see really the utility of wanting this information?
But anyway here is a small snippet that will fetch all used traits: https://3v4l.org/kvQGR
Best regards,
Gina P. Banyard