rfc:incompat_ctx

Differences

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

Link to this comparison view

Next revision
Previous revision
rfc:incompat_ctx [2012/07/30 17:20] – created cataphractrfc:incompat_ctx [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
-====== Request for Comments: How to write RFCs ======+====== Request for Comments: Remove calls with incompatible Context ====== 
 +An RFC for deprecating and removing <php>$this</php> from incompatible context. 
   * Version: 1.0   * Version: 1.0
   * Date: 2012-07-30   * Date: 2012-07-30
   * Author: Gustavo Lopes   * Author: Gustavo Lopes
-  * Status: Under Discussion+  * Status: Deprecation implemented in PHP 5.6
   * First Published at: http://wiki.php.net/rfc/incompat_ctx   * First Published at: http://wiki.php.net/rfc/incompat_ctx
  
 +===== Introduction =====
  
-An RFC for deprecating and removing `$thisfrom incompatible context.+This RFC proposes deprecating (in PHP 5.5) and removing (in the next version) the "<php>$this</php> from incompatible context" feature.
  
-===== Introduction =====+===== What this proposal is not about =====
  
-This RFC proposes deprecating (in PHP 5.5) and removing (in the next version) the "`$this` from incompatible context feature.+This proposal is not about removing static calls to instance methods or instance-like calls to static methods.
  
-==== The feature ====+===== The feature =====
  
 To be clear, the feature I'm proposing to remove is this: To be clear, the feature I'm proposing to remove is this:
  
-<php>+<code php>
 class A { class A {
     function foo() { var_dump(get_class($this)); }     function foo() { var_dump(get_class($this)); }
Line 26: Line 29:
 $b = new B; $b = new B;
 $b->bar(); //string(1) "B" $b->bar(); //string(1) "B"
-</php>+</code>
  
 Internal methods cannot be called in this fashion. 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 ===== ===== Rationale =====
  
-Method implementations almost always assume that $this refers to an instance of a compatible type. When they are called with an incompatible `$this`, there'll a bug most of the time. The only warning is an E_STRICT message, which many people have disabled.+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. 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.
Line 38: Line 50:
 When combined with LSB, it can be even more difficult to identify. See https://bugs.php.net/bug.php?id=62446 When combined with LSB, it can be even more difficult to identify. See https://bugs.php.net/bug.php?id=62446
  
- 
-===== What this proposal is not about ===== 
- 
-This proposal is not about removing static calls to instance methods or instance-like calls to static methods. 
  
 ===== BC break ===== ===== BC break =====
  
-The break should be minor. I very much doubt there are many lines of code that rely of it. It has been discouraged with an E_STRICT for a while.+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 [comment](http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_vm_def.h?r=80497ea7dfade2ccd032ef65103c0a113338653a#2335), exists only for compatibility with PHP 4. Far more used features legacy features, like register globals, have already been axed.+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. 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="True">
 +   * Yes
 +   * No
 +</doodle>
  
 ===== Changelog ===== ===== Changelog =====
  
   * 2012-07-30: Initial version   * 2012-07-30: Initial version
 +  * 2013-01-20: Opened vote 
 +  * 2013-01-28: Closed vote; RFC accepted unanimously with 15 votes in favor
rfc/incompat_ctx.1343668838.txt.gz · Last modified: 2017/09/22 13:28 (external edit)