From 831e67a5a82eea6fa6bc0df0371c86f7ace44ff0 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 5 Nov 2024 16:49:34 +0800 Subject: [PATCH 1/3] Add warn.deprecated.feature-8-4-0 to language-snippets.ent --- language-snippets.ent | 6 +++++- language/oop5/basic.xml | 4 +++- language/oop5/changelog.xml | 8 +++++++- reference/filesystem/functions/glob.xml | 7 ++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/language-snippets.ent b/language-snippets.ent index 498bb4e49..69a5bf91e 100644 --- a/language-snippets.ent +++ b/language-snippets.ent @@ -1,6 +1,6 @@ - + @@ -362,6 +362,10 @@ xmlns="http://docbook.org/ns/docbook">本特性已自 PHP 8.3.0 xmlns="http://docbook.org/ns/docbook">此函数自 PHP 8.3.0 起弃用。强烈建议不要应用此函数。'> +本特性已自 PHP 8.4.0 +起废弃。强烈建议不要使用本特性。'> + 此函数自 PHP 8.4.0 起弃用。强烈建议不要应用此函数。'> diff --git a/language/oop5/basic.xml b/language/oop5/basic.xml index bf0ce6aee..842840434 100755 --- a/language/oop5/basic.xml +++ b/language/oop5/basic.xml @@ -1,6 +1,6 @@ - + 基本概念 @@ -350,6 +350,8 @@ bool(true) format('Y'); +// 从 PHP 8.4.0 起,周围的括号是可选的 +echo new DateTime()->format('Y'); ?> ]]> diff --git a/language/oop5/changelog.xml b/language/oop5/changelog.xml index 8e6faa65b..364736e7f 100644 --- a/language/oop5/changelog.xml +++ b/language/oop5/changelog.xml @@ -1,6 +1,6 @@ - + OOP 变更日志 @@ -17,6 +17,12 @@ + + 8.4.0 + + 添加:支持 延迟对象。 + + 8.1.0 diff --git a/reference/filesystem/functions/glob.xml b/reference/filesystem/functions/glob.xml index 63e9eba79..8635ca4f3 100644 --- a/reference/filesystem/functions/glob.xml +++ b/reference/filesystem/functions/glob.xml @@ -1,6 +1,6 @@ - + @@ -66,10 +66,7 @@ flags - 有效标记有: - - - + 任何 GLOB_* 常量。 From d96598f718fefd1f79b5b7f50cf519b00cd51eeb Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 5 Nov 2024 16:59:26 +0800 Subject: [PATCH 2/3] Add lazy objects --- language/oop5/lazy-objects.xml | 483 +++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 language/oop5/lazy-objects.xml diff --git a/language/oop5/lazy-objects.xml b/language/oop5/lazy-objects.xml new file mode 100644 index 000000000..4acb1990c --- /dev/null +++ b/language/oop5/lazy-objects.xml @@ -0,0 +1,483 @@ + + + + + 延迟对象 + + + A lazy object is an object whose initialization is deferred 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 when 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 Properties 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. + + + From 9b9f40c658f142d318e43aeea5193eacfd3d788a Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 5 Nov 2024 21:28:02 +0800 Subject: [PATCH 3/3] sync oop5 --- language/oop5.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/language/oop5.xml b/language/oop5.xml index bed440507..de19601d1 100644 --- a/language/oop5.xml +++ b/language/oop5.xml @@ -1,7 +1,7 @@ - - + + 类与对象 @@ -47,6 +47,7 @@ &language.oop5.references; &language.oop5.serialization; &language.oop5.variance; + &language.oop5.lazy-objects; &language.oop5.changelog;