Hi
On 6/27/24 16:27, Arnaud Le Blanc wrote:
* flags should be a `list<SomeEnumAroundProxies>` instead. A bitmask for
a new API feels unsafe and anachronistic, given the tiny performance hit.
Unfortunately this leads to a 30% slowdown in newLazyGhost() when switching
to an array of enums, in a micro benchmark. I'm not sure how this would
impact a real application, but given this is a performance critical
I'm curious, how did the implementation look like? Is there a proof of
concept commit or patch available somewhere? As the author of the first
internal enum (Random\IntervalBoundary) I had the pleasure of finding
out that there was no trivial way to efficiently match the various enum
cases. See the PR review here:
https://github.com/php/php-src/pull/9679#discussion_r1045943444
I was able to find a hacky work-around, but if we add additional enums,
perhaps we should add the proper infrastructure to the arginfo files or
so to match enum cases to switch-case in C, even without making them an
integer-backed enum.
* what happens if `ReflectionClass#reset*()` methods are used on a
different class instance?
* considered?
The object must be an instance of the class represented by ReflectionClass
(including of a sub-class)
I believe the sub-class part is not spelled out in the RFC text. I'm
also not sure if allowing sub-classes here is sound, given the reasoning
of my previous emails.
* what about the object that a lazy proxy forwards state access to? Is
it cloned too?
Cloning an initialized proxy is the same as cloning the real instance (this
clones the real instance and returns it).
See my previous email.
After initialization, property accesses on the proxy are forwarded to
the actual instance.
Observing properties of the proxy has the same result as observing
properties of the actual instance.
* This is some sort of "quantum locking" of both objects?
* How hard is it to break this linkage?
* Can properties be `unset()`, for example?
* what happens to dynamic properties?
* I don't use them myself, and I discourage their usage, but it
would be OK to just document the expected behavior
The linkage can not be broken. unset() and dynamic properties are not
special, in that these are just property accesses. All property accesses on
the proxy are forwarded to the real instance.
The dynamic property bit is good, I had the same question. To rephrase:
Any access to a non-existant (i.e. dynamic) property will trigger
initialization and this is not preventable using
'skipLazyInitialization()' and 'setRawValueWithoutLazyInitialization()'
because these only work with known properties?
While dynamic properties are deprecated, this should be clearly spelled
out in the RFC for voters to make an informed decision.
`ReflectionClass::newLazyProxy()`
The factory should return a new object: the actual instance.
* what happens if the user mis-implements the factory as `function (object
$proxy): object { return $proxy; }`?
* this is obviously a mistake on their end, but is it somehow
preventable?
Returning a lazy object (including an initialized proxy) is not allowed and
will throw. I've clarified this in the RFC (the RFC specified that
returning a lazy object was not allowed, but whether this included
initialized proxies was not clear).
Relatedly: In the 'resetAsLazyGhost()' explanation we have this sentence:
> If the object is already lazy, a ReflectionException is thrown with
the message “Object is already lazy”.
What happens when calling the method on a *initialized* proxy object?
i.e. the following:
class Obj { public function __construct(public string $name) {} }
$obj1 = new Obj('obj1');
$r->resetAsLazyProxy($obj, ...);
$r->initialize($obj);
$r->resetAsLazyProxy($obj, ...);
What happens when calling it for the actual object of an initialized
proxy object? It's probably not possible to prevent this, but will this
allow for proxy chains? Example:
class Obj { public function __construct(public string $name) {} }
$obj1 = new Obj('obj1');
$r->resetAsLazyProxy($obj1, function () use (&$obj2) {
$obj2 = new Obj('obj2');
return $obj2;
});
$r->resetAsLazyProxy($obj2, function () {
return new Obj('obj3');
});
var_dump($obj1->name); // what will this print?
Best regards
Tim Düsterhus