diff --git a/language/oop5.xml b/language/oop5.xml index af325dce4103..7ddee2abc516 100644 --- a/language/oop5.xml +++ b/language/oop5.xml @@ -47,6 +47,7 @@ &language.oop5.references; &language.oop5.serialization; &language.oop5.variance; + &language.oop5.lazy-objects; &language.oop5.changelog; diff --git a/language/oop5/changelog.xml b/language/oop5/changelog.xml index 7cda045d0cad..628987236559 100644 --- a/language/oop5/changelog.xml +++ b/language/oop5/changelog.xml @@ -16,6 +16,12 @@ + + 8.4.0 + + Added: Support for Lazy Objects. + + 8.1.0 diff --git a/language/oop5/lazy-objects.xml b/language/oop5/lazy-objects.xml new file mode 100644 index 000000000000..36f9972b089b --- /dev/null +++ b/language/oop5/lazy-objects.xml @@ -0,0 +1,478 @@ + + + + Lazy Objects + + + A lazy object is an object whose initialization is defered until its + state is observed or modified. Some use-case examples include dependency + injection components that provide lazy services fully initialized only if + needed, ORMs providing lazy entities that hydrate themselves from + the database only when accessed, or a JSON parser that delays parsing until + elements are accessed. + + + + Two lazy object strategies are supported: Ghost Objects and Virtual + Proxies, hereafter referred to as "lazy ghosts" and + "lazy proxies". + In both strategies, the lazy object is attached to an initializer or factory + that is called automatically when its state is observed or modified for + the first time. From an abstraction point of view, lazy ghost objects are + indistinguishable from non-lazy ones: they can be used without knowing they + are lazy, allowing them to be passed to and used by code that is unaware of + laziness. Lazy proxies are similarly transparent, but care must be taken when + their identity is used, as the proxy and its real instance have different + identities. + + + + Creating Lazy Objects + + + It is possible to create a lazy instance of any user defined class or the + stdClass class (other internal classes are not supported), + or to reset an instance of these classes to make it lazy. The entry points + for creating a lazy object are the + ReflectionClass::newLazyGhost and + ReflectionClass::newLazyProxy methods. + + + + Both methods accept a function that is called the object requires + initialization. The function's expected behavior varies depending on the + strategy in use, as described in the reference documentation for each method. + + + + Creating a Lazy Ghost + + newLazyGhost(function (Example $object) { + // Initialize object in-place + $object->__construct(1); +}); + +var_dump($lazyObject); +var_dump(get_class($lazyObject)); + +// Triggers initialization +var_dump($lazyObject->prop); +?> + ]]> + + &example.outputs; + + +uninitialized(int) +} +string(7) "Example" +Example::__construct +int(1) +]]> + + + + + Creating a Lazy Proxy + + newLazyProxy(function (Example $object) { + // Create and return the real instance + return new Example(1); +}); + +var_dump($lazyObject); +var_dump(get_class($lazyObject)); + +// Triggers initialization +var_dump($lazyObject->prop); +?> + ]]> + + &example.outputs; + + +uninitialized(int) +} +string(7) "Example" +Example::__construct +int(1) +]]> + + + + + Any access to properties of a lazy object triggers its initialization + (including via ReflectionProperty). However, certain + properties might be known in advance and should not trigger initialization + when accessed: + + + + Initializing Oroperties eagerly + + newLazyGhost(function ($post) { + $data = fetch_from_store($post->id); + $post->__construct($data['id'], $data['title'], $data['content']); +}); + +// Without this line, the following call to ReflectionProperty::setValue() would +// trigger initialization. +$reflector->getProperty('id')->skipLazyInitialization($post); +$reflector->getProperty('id')->setValue($post, 123); + +// Alternatively, one can use this directly: +$reflector->getProperty('id')->setRawValueWithoutLazyInitialization($post, 123); + +// The id property can be accessed without triggering initialization +var_dump($post->id); +?> + ]]> + + + + + The ReflectionProperty::skipLazyInitialization and + ReflectionProperty::setRawValueWithoutLazyInitialization + methods offer ways to bypass lazy-initialization when accessing a property. + + + + + About Lazy Object Strategies + + + Lazy ghosts are objects that initialize in-place and, + once initialized, are indistinguishable from an object that was never lazy. + This strategy is suitable when we control both the instantiation and + initialization of the object, making it unsuitable if either of these is + managed by another party. + + + + Lazy proxies, once initialized, act as proxies to + a real instance: any operation on an initialized lazy proxy is forwarded + to the real instance. The creation of the real instance can be delegated + to another party, making this strategy useful in cases where lazy ghosts + are unsuitable. Although lazy proxies are nearly as transparent as lazy + ghosts, caution is needed when their identity is used, as the proxy and + its real instance have distinct identities. + + + + + Lifecycle of Lazy Objects + + + Objects can be made lazy at instantiation time using + ReflectionClass::newLazyGhost or + ReflectionClass::newLazyProxy, or after + instantiation by using + ReflectionClass::resetAsLazyGhost or + ReflectionClass::resetAsLazyProxy. Following this, a + lazy object can become initialized through one of the following operations: + + + + + Interacting with the object in a way that triggers automatic initialization. See + Initialization + triggers. + + + Marking all its properties as non-lazy using + ReflectionProperty::skipLazyInitialization or + ReflectionProperty::setRawValueWithoutLazyInitialization. + + + Calling explicitly ReflectionClass::initializeLazyObject + or ReflectionClass::markLazyObjectAsInitialized. + + + + + As lazy objects become initialized when all their properties are marked + non-lazy, the above methods will not mark an object as lazy if no properties + could be marked as lazy. + + + + + Initialization Triggers + + + Lazy objects are designed to be fully transparent to their consumers, + so normal operations that observe or modify the object’s state will + automatically trigger initialization before the operation is performed. This + includes, but is not limited to, the following operations: + + + + + Reading or writing a property. + + + Testing if a property is set or unsetting it. + + + Accessing or modifying a property via + ReflectionProperty::getValue, + ReflectionProperty::getRawValue, + ReflectionProperty::setValue, + or ReflectionProperty::setRawValue. + + + Listing properties with + ReflectionObject::getProperties, + ReflectionObject::getProperty, + get_object_vars + + + Iterating over properties of an object that does not implement + Iterator or IteratorAggregate using + foreach. + + + Serializing the object with serialize, + json_encode, etc. + + + Cloning the object. + + + + + Method calls that do not access the object state will not trigger + initialization. Similarly, interactions with the object that invoke magic + methods or hook functions will not trigger initialization if these methods + or functions do not access the object’s state. + + + + Non-Triggering Operations + + + The following specific methods or low-level operations allow access or + modification of lazy objects without triggering initialization: + + + + + Marking properties as non-lazy with + ReflectionProperty::skipLazyInitialization or + ReflectionProperty::setRawValueWithoutLazyInitialization. + + + Retrieving the internal representation of properties using + get_mangled_object_vars or by + casting the object to an + array. + + + Using serialize when + ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE is + set, unless + __serialize() or + __sleep() trigger initialization. + + + Calling to ReflectionObject::__toString. + + + Using var_dump or + debug_zval_dump, unless + __debugInfo() triggers + initialization. + + + + + + + Initialization Sequence + + + This section outlines the sequence of operations performed when + initialization is triggered, based on the strategy in use. + + + + Ghost Objects + + + The object is marked as non-lazy. + + + Properties not initialized with + ReflectionProperty::skipLazyInitialization or + ReflectionProperty::setRawValueWithoutLazyInitialization + are set to their default values, if any. At this stage, the object + resembles one created with + ReflectionClass::newInstanceWithoutConstructor, + except for already-initialized properties. + + + The initializer function is then called with the object as its first + parameter. The function is expected, but not required, to initialize + the object state, and must return &null; or no value. The object is no + longer lazy at this point, so the function can access its properties + directly. + + + + After initialization, the object is indistinguishable from an object that + was never lazy. + + + + + Proxy Objects + + + The object is marked as non-lazy. + + + Unlike ghost objects, the properties of the object are not modified at + this stage. + + + The factory function is called with the object as its first parameter and + must return a non-lazy instance of a compatible class (see + ReflectionClass::newLazyProxy). + + + The returned instance is referred to as the real + instance and is attached to the proxy. + + + The proxy’s property values are discarded as though + unset was called. + + + + After initialization, accessing any property on the proxy will + yield the same result as accessing the corresponding property on + the real instance; all property accesses on the proxy are forwarded + to the real instance, including declared, dynamic, non-existing, or + properties marked with + ReflectionProperty::skipLazyInitialization or + ReflectionProperty::setRawValueWithoutLazyInitialization. + + + The proxy object itself is not replaced or substituted + for the real instance. + + + While the factory receives the proxy as its first parameter, it is + not expected to modify it (modifications are allowed but will be lost + during the final initialization step). However, the proxy can be used + for decisions based on the values of initialized properties, the class, + the object itself, or its identity. For instance, the initializer might + use an initialized property’s value when creating the real instance. + + + + + Common Behavior + + + The scope and $this context of the initializer or factory + function remains unchanged, and usual visibility constraints apply. + + + + After successful initialization, the initializer or factory function + is no longer referenced by the object and may be released if it has no + other references. + + + + If the initializer throws an exception, the object state is reverted to its + pre-initialization state and the object is marked as lazy again. In other + words, all effects on the object itself are reverted. Other side effects, + such as effects on other objects, are not reverted. This prevents + exposing a partially initialized instance in case of failure. + + + + + + Cloning + + + Cloning a lazy object triggers its initialization before the clone is + created, resulting in an initialized object. + + + + For proxy objects, both the proxy and its real instance are cloned, and + the clone of the proxy is returned. The + __clone method is + called on the real instance, not on the proxy. The cloned proxy and real + instance are linked as they are during initialization, so accesses to + the proxy clone are forwarded to the real instance clone. + + + + This behavior ensures that the clone and the original object maintain + separate states. Changes to the original object or its initializer’s state + after cloning do not affect the clone. Cloning both the proxy and its real + instance, rather than returning a clone of the real instance alone, ensures + that the clone operation consistently returns an object of the same class. + + + + + Destructors + + + For lazy ghosts, the destructor is only called if the object has been + initialized. For proxies, the destructor is only called on the real instance, + if one exists. + + + + The ReflectionClass::resetAsLazyGhost and + ReflectionClass::resetAsLazyProxy methods may invoke + the destructor of the object being reset. + + + diff --git a/reference/reflection/reflectionclass.xml b/reference/reflection/reflectionclass.xml index 4ae52b580f87..a36085f99d16 100644 --- a/reference/reflection/reflectionclass.xml +++ b/reference/reflection/reflectionclass.xml @@ -56,6 +56,18 @@ int ReflectionClass::IS_READONLY + + public + const + int + ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE + + + public + const + int + ReflectionClass::SKIP_DESTRUCTOR + &Properties; @@ -140,6 +152,26 @@ + + ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE + + + Indicates that serialize should not trigger + initialization of a lazy object. + + + + + + ReflectionClass::SKIP_DESTRUCTOR + + + Indicates an object destructor should not be called when resetting it as + lazy. + + + + diff --git a/reference/reflection/reflectionclass/getlazyinitializer.xml b/reference/reflection/reflectionclass/getlazyinitializer.xml new file mode 100644 index 000000000000..3021b5d7e362 --- /dev/null +++ b/reference/reflection/reflectionclass/getlazyinitializer.xml @@ -0,0 +1,72 @@ + + + + ReflectionClass::getLazyInitializer + Gets lazy initializer + + + + &reftitle.description; + + public callablenullReflectionClass::getLazyInitializer + objectobject + + + Gets the lazy initializer or factory attached to + object. + + + + + &reftitle.parameters; + + + object + + + The object from which to get the initializer. + + + + + + + + &reftitle.returnvalues; + + Returns the initializer if the object is an uninitialized lazy + object, &null; otherwise. + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyGhost + + + + + + diff --git a/reference/reflection/reflectionclass/initializelazyobject.xml b/reference/reflection/reflectionclass/initializelazyobject.xml new file mode 100644 index 000000000000..1a78a5846c8a --- /dev/null +++ b/reference/reflection/reflectionclass/initializelazyobject.xml @@ -0,0 +1,132 @@ + + + + ReflectionClass::initializeLazyObject + Forces initialization of a lazy object + + + + &reftitle.description; + + public objectReflectionClass::initializeLazyObject + objectobject + + + Forces initialization of the specified object. This + method has no effect if the object is not lazy or has already been + initialized. Otherwise, initialization proceeds as described in the + Initialization + Sequence. + + + + + In most cases, calling this method is unnecessary, as lazy objects + initialize themselves automatically when their state is observed or + modified. + + + + + + &reftitle.parameters; + + + object + + + The object to initialize. + + + + + + + + &reftitle.returnvalues; + + If object is a lazy proxy, returns its real instance. + Otherwise, returns object itself. + + + + + &reftitle.examples; + + + Basic usage + +newLazyGhost(function ($object) { + echo "Initializer called\n"; + $object->__construct(1); +}); + +var_dump($object); + +$reflector->initializeLazyObject($object); + +var_dump($object); +?> +]]> + + &example.outputs; + + + uninitialized(int) +} +Initializer called +object(Example)#3 (1) { + ["prop"]=> + int(1) +} +]]> + + + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyGhost + ReflectionClass::markLazyObjectAsInitialized + ReflectionClass::isUninitializedLazyObject + + + + + + diff --git a/reference/reflection/reflectionclass/isuninitializedlazyobject.xml b/reference/reflection/reflectionclass/isuninitializedlazyobject.xml new file mode 100644 index 000000000000..74578db252e5 --- /dev/null +++ b/reference/reflection/reflectionclass/isuninitializedlazyobject.xml @@ -0,0 +1,115 @@ + + + + ReflectionClass::isUninitializedLazyObject + Checks if an object is lazy and uninitialized + + + + &reftitle.description; + + public boolReflectionClass::isUninitializedLazyObject + objectobject + + + Checks if an object is lazy and uninitialized. + + + + + &reftitle.parameters; + + + object + + + The object to check. + + + + + + + + &reftitle.returnvalues; + + Returns &true; if object is an uninitialized lazy + object, &false; otherwise. + + + + + &reftitle.examples; + + + Basic usage + +newLazyGhost(function ($object) { + echo "Initializer called\n"; + $object->__construct(1); +}); + +var_dump($reflector->isUninitializedLazyObject($object)); + +var_dump($object->prop); + +var_dump($reflector->isUninitializedLazyObject($object)); +?> +]]> + + &example.outputs; + + + + + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyGhost + ReflectionClass::markLazyObjectAsInitialized + ReflectionClass::initializeLazyObject + + + + + + diff --git a/reference/reflection/reflectionclass/marklazyobjectasinitialized.xml b/reference/reflection/reflectionclass/marklazyobjectasinitialized.xml new file mode 100644 index 000000000000..544768d00889 --- /dev/null +++ b/reference/reflection/reflectionclass/marklazyobjectasinitialized.xml @@ -0,0 +1,200 @@ + + + + ReflectionClass::markLazyObjectAsInitialized + Marks a lazy object as initialized without calling the initializer or factory + + + + &reftitle.description; + + public objectReflectionClass::markLazyObjectAsInitialized + objectobject + + + Marks a lazy object as initialized without calling the initializer or + factory. This has no effect if object is not lazy or + is already initialized. + + + The effect of calling this method is the same as described for Ghost Objects + (regardless of the laziness strategy of object) in + initialization + sequence, except that the initializer is not called. + After that, the object is indistinguishable from an object that was never + lazy and was created with + ReflectionClass::newInstanceWithoutConstructor, + except for the value of properties that were already initialized with + ReflectionProperty::setRawValueWithoutLazyInitialization + or ReflectionProperty::skipLazyInitialization. + + + + + &reftitle.parameters; + + + object + + + The object to mark as initialized. + + + + + + + + &reftitle.returnvalues; + + Returns object. + + + + + &reftitle.examples; + + + Marking an uninitialized lazy object as initialized + +newLazyGhost(function ($object) { + echo "Initializer called\n"; + $object->prop1 = 'initialized'; +}); + +$reflector->getProperty('prop1') + ->setRawValueWithoutLazyInitialization($object, 'prop1 value'); + +var_dump($object); + +$reflector->markLazyObjectAsInitialized($object); + +var_dump($object); +?> +]]> + + &example.outputs; + + + string(11) "prop1 value" + ["prop2"]=> + uninitialized(string) + ["prop3"]=> + uninitialized(string) +} +object(Example)#3 (2) { + ["prop1"]=> + string(11) "prop1 value" + ["prop2"]=> + uninitialized(string) + ["prop3"]=> + string(13) "default value" +} +]]> + + + + Marking an initialized object as initialized + +newLazyGhost(function ($object) { + echo "Initializer called\n"; + $object->prop1 = 'initialized'; +}); + +$reflector->getProperty('prop1') + ->setRawValueWithoutLazyInitialization($object, 'prop1 value'); + +var_dump($object->prop3); +var_dump($object); + +$reflector->markLazyObjectAsInitialized($object); + +var_dump($object); +?> +]]> + + &example.outputs; + + + string(11) "initialized" + ["prop2"]=> + uninitialized(string) + ["prop3"]=> + string(13) "default value" +} +object(Example)#3 (2) { + ["prop1"]=> + string(11) "initialized" + ["prop2"]=> + uninitialized(string) + ["prop3"]=> + string(13) "default value" +} +]]> + + + + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyGhost + ReflectionClass::initializeLazyObject + ReflectionClass::isUninitializedLazyObject + + + + + + diff --git a/reference/reflection/reflectionclass/newlazyghost.xml b/reference/reflection/reflectionclass/newlazyghost.xml new file mode 100644 index 000000000000..d10c92c0d9a6 --- /dev/null +++ b/reference/reflection/reflectionclass/newlazyghost.xml @@ -0,0 +1,188 @@ + + + + ReflectionClass::newLazyGhost + Creates a new lazy ghost instance + + + + &reftitle.description; + + public object ReflectionClass::newLazyGhost + callableinitializer + intoptions0 + + + Creates a new lazy ghost instance of the class, attaching the + initializer to it. The constructor is not called, and + properties are not set to their default value. However, the object will + be automatically initialized by invoking the + initializer the first time its state is observed or + modified. See + Initialization + Triggers and + Initialization Sequence. + + + + + &reftitle.parameters; + + + initializer + + + The initializer is a callback with the following signature: + + + + voidinitializer + objectobject + + + + object + + + The object being initialized. At this point, + the object is no longer marked as lazy, and accessing it does not + trigger initialization again. + + + + + + + The initializer function must return &null; or no + value. + + + + + options + + + options can be a combination of the following + flags: + + + + ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE + + + + By default, serializing a lazy object triggers its + initialization. Setting this flag prevents initialization, allowing + lazy objects to be serialized without being initialized. + + + + + + + + + + + + &reftitle.returnvalues; + + Returns a lazy proxy instance. If the object has no properties, or if all its + properties are static or virtual, a normal (non-lazy) instance is returned. + See also + Lifecycle of Lazy + Objects). + + + + + &reftitle.errors; + + An Error if the class is internal or extends an + internal class except stdClass. + + + + + &reftitle.examples; + + + Basic usage + +newLazyGhost(function (Example $object) { + $object->__construct(1); +}); + +var_dump($object); +var_dump($object instanceof Example); + +// Triggers initialization, and fetches the property after that +var_dump($object->prop); + +?> +]]> + + &example.outputs; + + + uninitialized(int) +} +bool(true) +Example::__construct +int(1) +]]> + + + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyProxy + ReflectionClass::newInstanceWithoutConstructor + ReflectionClass::resetAsLazyGhost + ReflectionClass::markLazyObjectAsInitialized + ReflectionClass::initializeLazyObject + ReflectionClass::isUninitializedLazyObject + ReflectionProperty::setRawValueWithoutLazyInitialization + ReflectionProperty::skipLazyInitialization + + + + + + diff --git a/reference/reflection/reflectionclass/newlazyproxy.xml b/reference/reflection/reflectionclass/newlazyproxy.xml new file mode 100644 index 000000000000..72a6e14b1ac4 --- /dev/null +++ b/reference/reflection/reflectionclass/newlazyproxy.xml @@ -0,0 +1,187 @@ + + + + ReflectionClass::newLazyProxy + Creates a new lazy proxy instance + + + + &reftitle.description; + + public objectReflectionClass::newLazyProxy + callablefactory + intoptions0 + + + Creates a new lazy proxy instance of the class, attaching the + factory function to it. The constructor is not + called, and properties are not set to their default values. When an + attempt is made to observe or modify the proxy’s state for the first + time, the factory function is called to provide a real instance, which + is then attached to the proxy. After this, all subsequent interactions + with the proxy are forwarded to the real instance. See + Initialization + Triggers and + Initialization Sequence. + + + + + &reftitle.parameters; + + + factory + + + The factory is a callback with the following signature: + + + + objectfactory + objectobject + + + + object + + + The object being initialized. At this point, + the object is no longer marked as lazy, and accessing it does not + trigger initialization again. + + + + + + + The factory function must return an object, referred to as the + real instance, which is then attached to the + proxy. This real instance must not be lazy and must not be the + proxy itself. If the real instance does not have the same class + as the proxy, the proxy’s class must be a subclass of the real + instance’s class, without additional properties, and must not override the + __destruct or __clone + methods. + + + + + options + + + See ReflectionClass::newLazyGhost. + + + + + + + + &reftitle.returnvalues; + + Returns a lazy proxy instance. If the object has no properties, or if all its + properties are static or virtual, a normal (non-lazy) instance is returned. + See also + Lifecycle of Lazy + Objects). + + + + + &reftitle.errors; + + See ReflectionClass::newLazyGhost. + + + + + &reftitle.examples; + + + Basic usage + +newLazyProxy(function (Example $object) { + $realInstance = new Example(1); + return $realInstance; +}); + +var_dump($object); +var_dump($object instanceof Example); + +// Triggers initialization, and forwards the property fetch to the real instance +var_dump($object->prop); + +var_dump($object); +?> +]]> + + &example.outputs; + + + uninitialized(int) +} +bool(true) +Example::__construct +int(1) +lazy proxy object(Example)#3 (1) { + ["instance"]=> + object(Example)#4 (1) { + ["prop"]=> + int(1) + } +} +]]> + + + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionClass::newLazyGhost + ReflectionClass::newInstanceWithoutConstructor + ReflectionClass::resetAsLazyProxy + ReflectionClass::markLazyObjectAsInitialized + ReflectionClass::initializeLazyObject + ReflectionClass::isUninitializedLazyObject + ReflectionProperty::setRawValueWithoutLazyInitialization + ReflectionProperty::skipLazyInitialization + + + + + + diff --git a/reference/reflection/reflectionclass/resetaslazyghost.xml b/reference/reflection/reflectionclass/resetaslazyghost.xml new file mode 100644 index 000000000000..d0ad8883c852 --- /dev/null +++ b/reference/reflection/reflectionclass/resetaslazyghost.xml @@ -0,0 +1,169 @@ + + + + ReflectionClass::resetAsLazyGhost + Resets an object and marks it as lazy + + + + &reftitle.description; + + public voidReflectionClass::resetAsLazyGhost + objectobject + callableinitializer + intoptions0 + + + Resets an existing object and marks it as lazy. + + + The object’s destructor is called (if one exists) unless the + ReflectionClass::SKIP_DESTRUCTOR flag is specified. In + the special case where the object is an initialized proxy, the real instance + is detached from the proxy. If the real instance is no longer referenced + elsewhere, its destructor is called regardless of the + SKIP_DESTRUCTOR flag. + + + Dynamic properties are removed, and the value of properties declared on the + class is discarded as though unset was called, and + marked as lazy. This implies that if the object is an instance of a subclass + with additional properties, these properties are not modified and not made + lazy. + Readonly + properties are also not modified and not made lazy if they are + final or the class itself is final. + + + If no properties was marked lazy, the object is is not marked as lazy. See + also + Lazy Objects + Lifecycle. + + + Otherwise, after calling this method, the behavior of the object is the same + as an object created by + ReflectionClass::newLazyGhost (except for + subclass and readonly properties, as described above). + + + The object is not replaced by an other one, and its identity remains + unchanged. Functionality such as spl_object_id, + spl_object_hash, + SplObjectStorage, WeakMap, + WeakReference, or + the identity operator + (===) are unaffected. + + + + + &reftitle.parameters; + + + object + + + A non-lazy object, or an initialized lazy object. + + + + + initializer + + + An initializer callback with the same signature and purpose as in + ReflectionClass::newLazyGhost. + + + + + options + + + options can be a combination of the following + flags: + + + + ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE + + + + By default, serializing a lazy object triggers its + initialization. Setting this flag prevents initialization, allowing + lazy objects to be serialized without being initialized. + + + + + + ReflectionClass::SKIP_DESTRUCTOR + + + + By default, the object destructor is called (if any) before making it + lazy. This provides safety regarding any preexisting state in the + object. This flag disables that behavior, allowing objects to be reset + as lazy without calling the destructor. + + + + + + + + + + + + &reftitle.returnvalues; + + &return.void; + + + + + &reftitle.errors; + + A ReflectionException if the object is lazy and + non-initialized. + + + An Error if the object is being initialized, or if the + object properties are being iterated with + foreach. + + + + + &reftitle.seealso; + + + ReflectionClass::newLazyGhost + ReflectionClass::resetAsLazyProxy + + + + + + diff --git a/reference/reflection/reflectionclass/resetaslazyproxy.xml b/reference/reflection/reflectionclass/resetaslazyproxy.xml new file mode 100644 index 000000000000..0a46cd43632e --- /dev/null +++ b/reference/reflection/reflectionclass/resetaslazyproxy.xml @@ -0,0 +1,106 @@ + + + + ReflectionClass::resetAsLazyProxy + Resets an object and marks it as lazy + + + + &reftitle.description; + + public voidReflectionClass::resetAsLazyProxy + objectobject + callablefactory + intoptions0 + + + The behavior of this method is the same as + ReflectionClass::resetAsLazyGhost except that it + uses the proxy strategy. + + + The object itself becomes the proxy. Similarly to + ReflectionClass::resetAsLazyGhost, the object is not + replaced by an other one, and its identity does not change, even after + initialization. The proxy and the real instance are distinct objects, with + distinct identities. + + + + + &reftitle.parameters; + + + object + + + A non-lazy object, or an initialized lazy object. + + + + + factory + + + An factory callback with the same signature and purpose as in + ReflectionClass::newLazyProxy. + + + + + options + + + The same flags as in + ReflectionClass::newLazyProxy. + + + + + + + + &reftitle.returnvalues; + + &return.void; + + + + + &reftitle.errors; + + See ReflectionClass::resetAsLazyGhost. + + + + + &reftitle.seealso; + + + ReflectionClass::newLazyProxy + ReflectionClass::resetAsLazyGhost + + + + + + diff --git a/reference/reflection/reflectionproperty/setrawvaluewithoutlazyinitialization.xml b/reference/reflection/reflectionproperty/setrawvaluewithoutlazyinitialization.xml new file mode 100644 index 000000000000..de8ed5ad32a3 --- /dev/null +++ b/reference/reflection/reflectionproperty/setrawvaluewithoutlazyinitialization.xml @@ -0,0 +1,89 @@ + + + + ReflectionProperty::setRawValueWithoutLazyInitialization + Set raw property value without triggering lazy initialization + + + + &reftitle.description; + + public voidReflectionProperty::setRawValueWithoutLazyInitialization + objectobject + mixednullvalue + + + Sets (changes) the property's value without triggering lazy initialization + and without calling hook functions. + The property is marked as non-lazy and can be accessed afterwards without + triggering lazy initialization. + The property must not be dynamic, static, or virtual, and the object must be + an instance of a user defined class or stdClass. + + + If this was the last lazy property, the object is marked as non-lazy and the + initializer or factory function is detached. + + + + + &reftitle.parameters; + + + object + + + The object to change the property on. + + + + + value + + + The new value. + + + + + + + + &reftitle.returnvalues; + + &return.void; + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionProperty::skipLazyInitialization + ReflectionClass::newLazyGhost + + + + + + diff --git a/reference/reflection/reflectionproperty/skiplazyinitialization.xml b/reference/reflection/reflectionproperty/skiplazyinitialization.xml new file mode 100644 index 000000000000..41305dfda6e6 --- /dev/null +++ b/reference/reflection/reflectionproperty/skiplazyinitialization.xml @@ -0,0 +1,79 @@ + + + + ReflectionProperty::skipLazyInitialization + Marks property as non-lazy + + + + &reftitle.description; + + public voidReflectionProperty::skipLazyInitialization + objectobject + + + Marks a property as non-lazy such that it can be accessed directly without + triggering lazy initialization. The property is initialized to its default + value, if any. + The property must not be dynamic, static, or virtual, and the object must be + an instance of a user defined class or stdClass. + + + If this was the last lazy property, the object is marked as non-lazy and the + initializer or factory function is detached. + + + + + &reftitle.parameters; + + + object + + + The object to mark the property on. + + + + + + + + &reftitle.returnvalues; + + &return.void; + + + + + &reftitle.seealso; + + + Lazy objects + ReflectionProperty::setRawValueWithoutLazyInitialization + ReflectionClass::newLazyGhost + + + + + + diff --git a/reference/reflection/versions.xml b/reference/reflection/versions.xml index a868b02e448b..9fd76dcef619 100644 --- a/reference/reflection/versions.xml +++ b/reference/reflection/versions.xml @@ -216,6 +216,14 @@ + + + + + + + + @@ -329,6 +337,8 @@ + +