rfc:incompat_ctx
no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


Previous revision
Next revision
rfc:incompat_ctx [2013/01/20 19:22] – [Request for Comments: Remove calls with incompatible Context] cataphract
Line 1: Line 1:
 +====== Request for Comments: Remove calls with incompatible Context ======
 +An RFC for deprecating and removing <php>$this</php> from incompatible context.
  
 +  * Version: 1.0
 +  * Date: 2012-07-30
 +  * Author: Gustavo Lopes
 +  * Status: Voting phase
 +  * First Published at: http://wiki.php.net/rfc/incompat_ctx
 +
 +===== Introduction =====
 +
 +This RFC proposes deprecating (in PHP 5.5) and removing (in the next version) the "<php>$this</php> from incompatible context" feature.
 +
 +===== What this proposal is not about =====
 +
 +This proposal is not about removing static calls to instance methods or instance-like calls to static methods.
 +
 +===== The feature =====
 +
 +To be clear, the feature I'm proposing to remove is this:
 +
 +<code php>
 +class A {
 +    function foo() { var_dump(get_class($this)); }
 +}
 +class B {
 +   function bar() { A::foo(); }
 +}
 +$b = new B;
 +$b->bar(); //string(1) "B"
 +</code>
 +
 +Internal methods cannot be called in this fashion.
 +
 +===== The Change ====
 +
 +Even though I think an error at call site would be the most useful to the user, the most sensible option is to just have <php>$this === null</php> inside the callee, like when you do:
 +
 +<code php>
 +class A { function foo() {} }
 +A::foo(); // E_STRICT
 +</code>
 +
 +===== Rationale =====
 +
 +Method implementations almost always assume that $this refers to an instance of a compatible type. When they are called with an incompatible <php>$this</php>, there'll a bug most of the time. The only warning is an <php>E_STRICT</php> message, which many people have disabled.
 +
 +Because this feature is surprising and little-known, a simple error like calling Class::foo() instead of ::fooStatic() (when foo() and fooStatic() have similar names), by not failing on the call site, can be difficult to identify.
 +
 +When combined with LSB, it can be even more difficult to identify. See https://bugs.php.net/bug.php?id=62446
 +
 +
 +===== BC break =====
 +
 +The break should be minor. I very much doubt there are many lines of code that rely on this feature. It has been discouraged with an <php>E_STRICT</php> since 2006 (see [[https://github.com/php/php-src/commit/6f76b170|6f76b170]]).
 +
 +This feature, as noted in the [[http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_vm_def.h?r=80497ea7dfade2ccd032ef65103c0a113338653a#2335|comment]], exists only for compatibility with PHP 4. Far more used legacy features, like register globals, have already been axed.
 +
 +This feature can, however, be used to implement trait-like behavior, and I'm sure someone somewhere did such a thing.
 +
 +===== Alternatives =====
 +
 +Using traits is perhaps the easiest and cleanest way to replace code that relies on the feature to be removed. Changing the code to use traits implies: 1) refactoring the instance methods called from incompatible contexts into a trait, 2) make the callers from incompatible contexts use the new trait, 3) change the call sites to use <php>$this->method()</php> instead of <php>OrigClass::method()</php>. Example:
 +
 +<code php>
 +<?php
 +class A {
 + function dumpClass() {
 + var_dump(get_class($this));  
 + }
 +}
 +class B {
 + function test() {
 + A::dumpClass();
 + }
 +}
 +
 +$a = new A;
 +$b = new B;
 +$a->dumpClass();
 +$b->test();
 +</code>
 +
 +would become:
 +
 +<code php>
 +<?php
 +trait ATrait {
 + function dumpClass() {
 + var_dump(get_class($this));  
 + }
 +}
 +class A {
 + use ATrait;
 +}
 +class B {
 + use ATrait;
 + function test() {
 + $this->dumpClass();
 + }
 +}
 +
 +$a = new A;
 +$b = new B;
 +$a->dumpClass();
 +$b->test();
 +</code>
 +
 +A worse solution, which relies on the possibility of calling instance methods statically would be using an extra parameter:
 +
 +<code php>
 +<?php
 +class A {
 + function dumpClass($obj=null) {
 + if ($obj === null)
 + $obj = $this;
 + var_dump(get_class($obj));  
 + }
 +}
 +class B {
 + function test() {
 + A::dumpClass($this); //E_STRICT ($this would be NULL on callee)
 + }
 +}
 +
 +$a = new A;
 +$b = new B;
 +$a->dumpClass();
 +$b->test();
 +</code>
 +
 +===== Vote =====
 +
 +Voting ends not before Monday, January 28th 2013. The PHP language is ultimately changed, so a 2/3 majority is required.
 +
 +<doodle 
 +title="Deprecate calls with incompatible context in 5.5 and disallow them in the version after (be it 5.6 or 6.0)" auth="cataphract" voteType="single" closed="False">
 +   * Yes
 +   * No
 +</doodle>
 +
 +===== Changelog =====
 +
 +  * 2012-07-30: Initial version
 +  * 2012-01-20: Opened vote
rfc/incompat_ctx.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1