Hi internals, As part of [1] and [2] we have decided to remove support for doing static calls to instance methods, if this would result in an incompatible $this variable to be used. When applying [3] this change we found that the change as originally intended may be too strict. To provide an example (the comments are the important bit):
class A { // This is an *instance* method, but it doesn't actually use $this. // This kind of usage is very common in PHP 4 era code, where // "static" annotations weren't used function test() { echo "foo"; } } class B { function test2() { // This call would be forbidden because it assumes $this of class B, when // calling an instance method of class A. However A::test() does not actually // use $this! A::test(); } } This case, where an incompatible $this will be assumed, but never actually used, seems to be very common in PEAR, for example. Another weirdness of forbidding this call is that the following very similar code would work and only throw an E_STRICT notice: // NOT in a class function test3() { A::test(); // E_STRICT } I don't think having this kind of asymmetry is good. Doing A::test() should behave the same whether I use it a function, static method or instance method. (Ignoring scoped call with compatible $this here.) To remove this asymmetry we could completely forbid calling instance methods statically (ignoring the case of compatible $this again), but I suspect this may not be a popular option as this has been only partially deprecated previously. The compromise I'd like to implement instead is to only throw a fatal error if $this is actually used in the called method and otherwise throw a deprecation warning. Calls from instance methods, static methods and functions will all be handled the same. A PR with this behavior is available [4]. To clarify what this entails, a few examples: class A { // Instance method does NOT use $this function test() { echo "foo"; } } // As such all of the following are valid and only throw a deprecation warning class B { function test2() { A::test(); // E_DEPRECATED } static function test3() { A::test(); // E_DEPRECATED } } A::test(); // E_DEPRECATED So in this example $this wasn't used and all calls are valid (but deprecated). Now an example using $this: class A { // Instance method DOES use $this function test() { var_dump($this); } } // As such all of the following are NOT allowed: class B { function test2() { A::test(); // E_ERROR } static function test3() { A::test(); // E_ERROR } } A::test(); // E_ERROR Whether $this is used is detected at compile-time (by amending the already existing ALLOW_STATIC flag). Of course we cannot detect variable-variable usages, in which case $this will be an undefined variable (as it was already the case for calls from outside instance methods): class A { // Uses $this, but we can't detect it function test() { $name = 'this'; var_dump($$this); } } class B { function test2() { A::test(); // Throws E_DEPRECATED // Followed by E_NOTICE for undefined $this variable } } Furthermore it should be mentioned what isn't affected at all by this change: "Static" calls with a compatible $this. E.g. parent::__construct() will continue to work fine like it already does, without any deprecations etc. I think this change makes more sense than the original implementation - it is symmetric for all static calls and has less BC impact. One case that will still be broken is code checking whether $this is set [5] to have different behavior for instance and static calls. However this usage is a lot more rare and rather questionable in itself. Any objections to implement the incompatible context removal this way? Thanks, Nikita [1]: https://wiki.php.net/rfc/incompat_ctx [2]: https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7 [3]: https://github.com/php/php-src/commit/dc9991b167533c7ee13ff96da6048988e6e31bc2 [4]: https://github.com/php/php-src/pull/1026 [5]: https://github.com/pear/pear-core/blob/stable/PEAR.php#L652