[DeepClone] Fix round-tripping objects whose __serialize() nests another object#629
Merged
Merged
Conversation
…her object A needsFullUnserialize object (a final internal class with __unserialize that rejects an empty payload, e.g. Random\Randomizer) whose __serialize() nests another object carries an object-ref mask on its state. Such an object cannot be built as an early empty shell, and the eager-finalize pass skipped masked states, leaving a null placeholder; when another object referenced it, the properties loop threw "unknown object id" before the states loop could reconstruct it. These objects are now finalized to a fixpoint after the refs pass, once the objects their mask references exist. Round-tripping Random\Randomizer as an object property (or deeper) now works, matching the extension. A shared object nested inside such a state is still reconstructed as an independent copy (pure PHP cannot inject a live shared object into an internal final class's __unserialize); the extension preserves identity there.
b3cced5 to
daa74de
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #628 (which adds the states-loop guard this relies on).
A
needsFullUnserializeobject (afinalinternal class whose__unserialize()rejects an empty payload, so it has no empty-shell prototype) whose__serialize()nests another object carries an object-ref mask on its reconstruction state.Random\Randomizer, which wraps aRandom\Engine\*, is the common case.reconstruct()defers these to the states loop, but the eager-finalize pass that turns deferred objects into real instances (so the properties loop can resolve references to them) skipped any state with an object-ref mask. The placeholder stayednull, and as soon as another object referenced it the properties loop threwdeepclone_from_array(): ... unknown object id. The extension does not have this problem: it instantiates every object shell up front viaobject_init_ex()and calls__unserialize()later.Reproducer (works with the extension, threw with the polyfill):
These objects are now finalized to a fixpoint after the refs pass, once the objects their mask references exist (a remaining cycle, which pure PHP cannot reconstruct, is still reported by the existing loops).
Random\Randomizernow round-trips as an object property, top-level, in arrays and nested.Known limitation: a shared object nested inside such a state is reconstructed as an independent copy, because pure PHP cannot inject a live shared object into an internal
finalclass's__unserialize(). The extension preserves identity in that case. This only affects an object shared between aneedsFullUnserializeobject's serialized state and the rest of the graph.