Re: [RFC] Lazy Objects
| From: | Tim Düsterhus | Date: | Sun, 30 Jun 2024 13:08:40 +0000 |
| Subject: | Re: [RFC] Lazy Objects | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-124090@lists.php.net to get a copy of this message | ||
Hi
I finally got around to giving the RFC another read. Please apologize if this email asks questions that have already been answered elsewhere, as the current mailing list volume makes it hard for me to keep up.
On 6/14/24 14:13, Arnaud Le Blanc wrote:
Okay. But the RFC (and your email) does not explain why I would want do that. It appears that much of the RFC's complexity (e.g. around readonly properties and destructors) stems from the wish to support turning an existing object into a lazy object. If there is no strong reason to support that, I would suggest dropping that. It could always be added in a future PHP version.Is there any reason to call the makeLazyX() methods on an object that was not just freshly created with ->newInstanceWithoutConstructor() then?There are not many reasons to do that. The only indented use-case that doesn't involve an object freshly created with ->newInstanceWithoutConstructor() is to let an object manage its own laziness by making itself lazy in its constructor:
I've read the updated RFC and it's still not clear to me that returning an arbitrary “actual instance” object is sound. Especially when private properties - which for all intents and purposes are not visible outside of the class - are involved. Consider the following:The 'A' object is what is called the "actual instance" in the RFC. $o acts as a proxy to the actual instance: Any property access on $o is forwarded to the actual instance A.I don't understand what happens with the 'A' object then, but perhaps this will become clearer once you add the requested examples.- The return value of the initializer has to be an instance of a parent or a child class of the lazy-object and it must have the same properties. Would returning a parent class not violate the LSP? Consider the following example:$o->foo() calls B::foo() in both cases here, as $o is always the proxy object. We need to double check, but we believe that this rule doesn't break LSP.class A { public string $s; } class B extends A { public function foo() { } }$o = new B(); ReflectionLazyObject::makeLazyProxy($o, function (B $o) { return new A(); });$o->foo(); // works $o->s = 'init'; $o->foo(); // breaks
class A {
public function __construct(
public string $property,
) {}
}
class B extends A {
public function __construct(
string $property,
private string $foo,
) { parent::__construct($property); }
public function getFoo() {
return $this->foo;
}
}
$r = new ReflectionClass(B::class);
$obj = $r->newLazyProxy(function ($obj) {
return new A('value');
});
var_dump($obj->property); // 'value'
var_dump($obj->getFoo()); // Implicitly accesses A::${'\0B\0foo'} (i.e. the mangled B::$foo property)?
Now you might say that B does not have the same properties as A and creating the proxy is not legal, but then the addition of a new private property would immediately break the use of the lazy proxy, which specifically is something that private properties should not be able to do.
Best regards
Tim Düsterhus