+
+ 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 @@
intReflectionClass::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;
+
+ publiccallablenullReflectionClass::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;
+
+ publicobjectReflectionClass::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;
+
+ publicboolReflectionClass::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;
+
+ publicobjectReflectionClass::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;
+
+ publicobjectReflectionClass::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;
+
+ publicobjectReflectionClass::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;
+
+ publicvoidReflectionClass::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;
+
+ publicvoidReflectionClass::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;
+
+ publicvoidReflectionProperty::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;
+
+ publicvoidReflectionProperty::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 @@
+
+