[IDEA for RFC] class_uses and optionally returning traits for parent classes

php.internals

Robert Humphries

160 days ago
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

Claude Pache

160 days ago
> 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

Robert Humphries

160 days ago
>> 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

Gina P. Banyard

160 days ago
On Wednesday, 25 March 2026 at 07:40, Robert Humphries <contact@developer-rob.co.uk> wrote:
> 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?
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

Robert Humphries

135 days ago
Sorry for the delay here, been quite busy with other work related tasks.
> 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.
I don't necessarily disagree with this, especially about SPL in general; however we are at a point where we have them currently (and the functions are not deprecated/warned against use/etc). That said, I certainly wouldn't be suggesting adding the function if it didn't already exist.
> 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.
Note with this, the same constraints apply to parent classes in terms of the information stored in C - and `ReflectionClass` will return only the parent as opposed to grandparents/etc; but `class_parents` returns the parent class / grandparent class / etc. I think this is the strongest argument for making such a change to `class_uses` - currently it is inconsistent with the other SPL functions (and I wouldn't say that modifying the function is going to cause millions of developers to start using the function, it is more about making the behaviour a little more consistent).
> The current API doesn't even tell you if used traits also use other traits.
As per your example, `ReflectionClass::getTraits` also does not tell you about any traits used by other traits, you need to query the ReflectionClass for the trait returned by 'getTraits'. `class_uses` will also accept a trait for `$object_or_class`, returning the traits that trait uses. I would suggest that if a change was made to class_uses to support optionally returning inherited traits then it returning traits used on traits or the parent class would make sense.
> 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.
`class_uses` seems to just return the names of the traits (mirroring `getTraitNames` on `ReflectionClass` as far as I can tell).
> 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
In a private / tightly controlled codebase we are using a set of traits to implement certain functionality at a higher level in the inheritance chain; and then where needed checking for the existence of the trait to tell if the functionality is supported or not (think along the lines of if a trait could implement an interface). There are various reasons why it isn't easily possible to use interfaces directly on the relevant classes themselves in the particular codebase (mainly related to refactoring work required as opposed to technical reasons) - currently we have gone with a reduced version of the example code (as we only need to know the names of traits implemented by the classes as opposed to from traits using traits for our exact use-case). (As a quick side note, what I am really looking for proposal 2 from https://wiki.php.net/rfc/traits-with-interfaces (or a form of `trait` that does this) and then using traits with interfaces for composition, however from what I can see on activity such as GH-11435 technical reasons mean this isn't likely to proceed). ---- I guess the important questions is that regardless of the people's thoughts on the functions themselves, what are the benefits/disadvantages of making the change to the pre-existing function (and if there are more benefits compared to disadvantages, do those benefits justify introducing the change)? The example code proves that the information can be gained from userland code; but the code isn't a straight forward example - and I suspect it is a lot slower (however you are not likely to do a large number of calls to the userland or internals code). I still think personally is the biggest benefit is it brings the behaviour of the three `class_XXXX` functions in SPL fully inline with each other (that they all return the parents/interfaces/traits that the class or any related classes/traits use); and I am not seeing any disadvantages except that the change not necessary (but I don't think any implementation would be complex or hard to maintain - my thoughts here would it would basically be the `while` in `php_spl.c` lines 125-128 (in `class_parents`) plus if it was decided to include traits included by traits then a similar check or recursive call to get traits used by each trait in the array).

Claude Pache

134 days ago
> Le 19 avr. 2026 à 21:01, Robert Humphries <contact@developer-rob.co.uk> a écrit : > > I think this is > the strongest argument for making such a change to `class_uses` - > currently it is inconsistent with the other SPL functions (and I > wouldn't say that modifying the function is going to cause millions of > developers to start using the function, it is more about making the > behaviour a little more consistent).
I think that `class_uses()` should never have been implemented, because it gives a false sense of symmetry with `class_implements()` and `class_parents()`. Implemented interfaces and parent classes can be used as types on the corresponding object (and types are inherited), while used traits cannot. Those are fundamentally different concepts. If, for some reason, you want to “cheat” and use traits as if they were inherited types, you are free to do that, but I don’t think that PHP should provide a built-in function that goes beyond what traits are intended for.
> > (As a quick side note, what I am really looking for proposal 2 from > https://wiki.php.net/rfc/traits-with-interfaces (or a form of `trait` > that does this) and then using traits with interfaces for composition, > however from what I can see on activity such as GH-11435 technical > reasons mean this isn't likely to proceed).
See also https://wiki.php.net/rfc/interface-default-methods, which is, I think, what is really needed. —Claude

Anton Smirnov

134 days ago
On 20/04/2026 12:32, Claude Pache wrote:
> I think that `class_uses()` should never have been implemented, because > it gives a false sense of symmetry with `class_implements()` and > `class_parents()`. Implemented interfaces and parent classes can be used > as types on the corresponding object (and types are inherited), while > used traits cannot. Those are fundamentally different concepts.
I agree
> If, for some reason, you want to “cheat” and use traits as if they were > inherited types, you are free to do that, but I don’t think that PHP > should provide a built-in function that goes beyond what traits are > intended for.
That won't even work reliably. You can rename trait methods and override them with methods with incompatible signatures and do other similar stuff to make this use case a nightmare. Therefore this:
>> and then where needed checking for the existence of >> the trait to tell if the functionality is supported or not (think >> along the lines of if a trait could implement an interface).
is totally impossible to do. A trait with a method does not guarantee you that the method is available. Anton