|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70437 Changes to static properties in trait methods are not reflected in the class
Submitted: 2015-09-06 14:32 UTC Modified: 2021-07-23 07:35 UTC
Avg. Score:3.5 ± 0.9
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: Assigned: nikic (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 7.0.0RC2 OS: OSX/Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Bug Type:
New email:
PHP Version: OS:


 [2015-09-06 14:32 UTC]
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.

Test script:
Static methods:
Instance methods:

Expected result:
Should modify the inherited-from-trait static property within the class

Actual result:
Modifies a trait-specific copy of the static property


Add a Patch

Pull Requests

Pull requests:

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2015-09-07 03:53 UTC]
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.
 [2015-09-07 09:15 UTC]
-Status: Open +Status: Assigned -Assigned To: +Assigned To: bwoebi
 [2015-09-07 09:15 UTC]
Totally agreeing with Nikita here; I've just attached a small PR:
 [2015-09-07 10:39 UTC]
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.
 [2015-09-07 10:45 UTC]
Did you checkout the patch? It's always accessing the class' static property now as far as I see?
 [2015-09-07 11:02 UTC]
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.
 [2015-09-07 11:10 UTC]
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.
 [2016-03-08 20:53 UTC] eric at ericstern dot com
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:
Works as expected:
Access not allowed:

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.
 [2021-07-22 10:57 UTC]
Calling static trait methods is deprecated as of PHP 8.1.0, so
there is *some* progress here.
 [2021-07-23 07:35 UTC]
-Status: Assigned +Status: Closed -Assigned To: bwoebi +Assigned To: nikic
 [2021-07-23 07:35 UTC]
Right, I believe we can close this. Static properties in traits are not supposed to be shared between using classes. The specific case where they are used on the trait itself is being removed. The behavioral discrepancy noted by eric is resolved by (modifications of the trait static props will have no effect on using classes, even if they happen prior to use).
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Thu Jul 29 16:01:24 2021 UTC