On 29 March 2016 at 23:21, Nikita Popov <nikita....@gmail.com> wrote:
> Hi internals! > > Currently, inside instance methods the following invariant holds: > > assert(is_null($this) || is_object($this)) > > This is a problem. I'd like to guarantee the following invariant instead: > > assert(is_null($this) || $this instanceof self) > > That is, ensure that if $this is not null, then it must be an object > "compatible" with the class, i.e. be in its inheritance hierarchy. > > The absence of this guarantee, apart from being a major WTF in itself, also > prevents us from optimizing operations involving $this. In particular, the > following optimizations are not possible: > > a) If typed properties land, we will not be able to use the type of > $this->typedProperty for optimization, because $this->typedProperty might > actually be referencing a property of a totally unrelated class. > b) We are not able to early-bind arguments to private or final method > calls, i.e. determine at compile-time whether an argument will use by-value > or by-reference argument passing and optimize accordingly. > c) We are not able to inline calls to private or final methods. (The > possibility of null is an issue in this instance as well, though a lesser > one.) > > The good news is that, as of PHP 7.0, we are *very* close to guaranteeing > that "$this instanceof self" already. There exists only one little known > loophole: Obtaining a closure object wrapping the method using > ReflectionMethod::getClosure() and binding to an unrelated $this using > Closure::bindTo(). > > In PHP 7.0 we already heavily cut down [1] on what bindTo() is to allowed > to do on fake method closures. Namely, it was completely forbidden to > rebind the scope of methods, as this was already interacting badly with > optimizations in 7.0. We did not forbid binding to an incompatible $this > because it was not yet causing immediate issues at the time. > > I'd like to remedy this oversight now and restrict $this binding of fake > method closures to compatible contexts only, i.e. for a method A::foo() > allow only instances of A or one of its descendant classes to be bound. > This limitation already exists for fake method closures targeting internal > methods. > > Are there any objections to this change? If not, I'll merge the patch [2]. > If yes, I'll write an RFC, as this change, while of no direct consequence > for PHP programmers, is important for the PHP implementation. > > Regards, > Nikita > > [1]: http://markmail.org/message/sjihplebuwsmdwex > [2]: > https://github.com/php/php-src/compare/master...nikic:forbigIncompatThis > Hi, Will this patch break any use cases similar to: class Bar { private $a = 'hidden'; } $x = new Bar(); $y = function() { return $this->a); $z = $x->bindTo($x, $x); echo $z(); //hidden ? If not, I have no objections.