go to bug id or search bugs for
If you have a trait that defines a static property, and you modify said property from within a trait inherited method, the modifications are done to a trait instance of the property, as opposed to the inherited-from-trait static property within the class.
The behavior differs slightly in PHP 5.4.7 - 5.5.29 in that if the methods are instance methods, then they will correctly modify the inherited-from-trait static property, but are broken for static methods. 5.6.0+ has the same behavior for static and instance methods.
Static methods: https://3v4l.org/UZ6gq
Instance methods: https://3v4l.org/piUFm
Should modify the inherited-from-trait static property within the class
Modifies a trait-specific copy of the static property
Add a Patch
Add a Pull Request
Imho the bug here is that we allow calls to static methods on traits. I don't think that's supposed to work and we should add this forgotten check in PHP 7.
Totally agreeing with Nikita here; I've just attached a small PR: https://github.com/php/php-src/pull/1506
The issue isn't when calling the method directly on the trait but also when calling it on the implementing class. Any changes to static properties within trait methods called on the implementing class are only reflected within the traits copy of it; rather than the implementing classes copy as it should be.
Did you checkout the patch? It's always accessing the class' static property now as far as I see?
This is by design, changing that is a BC issue.
The design is chosen based on the desired 'copy-down' semantics of traits.
Static properties of traits are independent of the ones of classes using the trait.
Changing it means you break the copy-down semantics by adding another corner case where it is not consistent.
Is it by design?
We don't know, it's neither documented nor mentioned in the original RFC.
Heck, the RFC itself proposed even a singleton trait.
With current semantics that trait could be used only exactly once, because the trait shares the static property. I guess that's not the purpose of traits, it's about horizontal *reuse*. Hence each class should have its own static properties and never use the static property of the trait.
Also, by the way, if they were supposed to be independent, then the classes shouldn't be copied the traits static properties (and methods too) into them.
We should have one or the other behavior, but having both behaviors is very confusing.
I'm experiencing this (or at least something very similar) as well, and have some additional information which may or may not be relevant:
If you call a static method that sets a property on the trait before a class uses it, that property is copied across. If the class is what triggers the trait to load and that same setter is called after the class using the trait is loaded (but still before access to that property), the value is null. Basically, the autoload order matters.
While the examples below may not quite follow the original RFC's intent, I think it's fairly obvious what the code's intent is (conceivably, setting the same static property on all classes that use a given trait)
Interestingly, trying to use the trait's name instead of self errors out with invalid property access, even though the intent is *even* more obviously to get the value out of the trait. This case has completely unambiguous intent, but fails the worst.
Null property: https://3v4l.org/4pXor
Works as expected: https://3v4l.org/428lo
Access not allowed: https://3v4l.org/Lk3ll
tl;dr: `self` doesn't really work as an end-user would expect in traits. Maybe it should have been prevented outright in the initial design, but that ship has sailed. As someone just writing code (and not PHP internals), I expect static properties defined in traits to be shared across everything using that trait, even though that's not semantically in line with "compiler-assisted copy and paste"
For context, the main use case (for me) is to avoid injecting the same configuration change in thirty places, which is totally in line with the actual intent of using traits to write DRY code.