Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:82535 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 85862 invoked from network); 12 Feb 2015 14:24:26 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 12 Feb 2015 14:24:26 -0000 Authentication-Results: pb1.pair.com smtp.mail=nikita.ppv@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=nikita.ppv@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.172 as permitted sender) X-PHP-List-Original-Sender: nikita.ppv@gmail.com X-Host-Fingerprint: 74.125.82.172 mail-we0-f172.google.com Received: from [74.125.82.172] ([74.125.82.172:52870] helo=mail-we0-f172.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id AF/66-50473-797BCD45 for ; Thu, 12 Feb 2015 09:24:25 -0500 Received: by mail-we0-f172.google.com with SMTP id k48so10417470wev.3 for ; Thu, 12 Feb 2015 06:24:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=OH1/5MaQheML58U6G1IRRFY3OVjMXdXhzXEHSpowJkk=; b=i7/soWVKjBcZmUlfhh2rTKiruaLzGT8I104OdSiE41jEjsj7toAq48TkXBoGbhUGSQ 1UIFnY8TKL8JqAseV9vgichUBaM8SkD6IoGBftSCQ0VyPfajzV/FkCIea8+bgZuluAO6 MVY8yIitWmomr93XHapBlHQ9ttpyePS73p8lYDJQ1BIqx8Y3n07rzCGhdxaKb1NvJHGX XU3CJD7LVnTHfStIIA4YxYRcxds+S2oKa4PJumphH7IvzGw/x/dyFEzKvcGfZqhv9iQ5 uOPqRRxdhjzNA5qdJdONvKvdYgEvynAcYH26TLVulAeZRDj5xe5GtMZdvJ0E7DHBcAY6 jHpA== MIME-Version: 1.0 X-Received: by 10.180.206.14 with SMTP id lk14mr6602403wic.71.1423751060576; Thu, 12 Feb 2015 06:24:20 -0800 (PST) Received: by 10.27.10.168 with HTTP; Thu, 12 Feb 2015 06:24:20 -0800 (PST) Date: Thu, 12 Feb 2015 15:24:20 +0100 Message-ID: To: PHP internals Content-Type: multipart/alternative; boundary=001a11c38dac36deee050ee4e0d1 Subject: Remove $this from incompatible context From: nikita.ppv@gmail.com (Nikita Popov) --001a11c38dac36deee050ee4e0d1 Content-Type: text/plain; charset=UTF-8 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 --001a11c38dac36deee050ee4e0d1--