Preserve references on dynamic properties - #41
Merged
Merged
Conversation
nicolas-grekas
force-pushed
the
dynamic-property-refs
branch
from
September 23, 2026 07:11
3eee449 to
4fdeb56
Compare
deepclone_to_array() now keeps shared references on dynamic properties too, on objects with the standard property handlers, and deepclone_from_array() binds them to the properties table like unserialize() does, instead of rejecting such payloads. The deprecation their creation raised on the origin is not reported again. Readonly classes still reject them, as do virtual properties and objects with custom property handlers. zend_std_write_property() only accepts dereferenced values, which the lazy-ghost replay of deepclone_from_array() and deepclone_hydrate() with DEEPCLONE_HYDRATE_PRESERVE_REFS did not ensure: a reference targeting a dynamic property, a hooked property or a property of an uninitialized lazy object aborted debug builds. Dynamic properties and lazy objects, once initialized, now get the reference, and hooked properties the value.
nicolas-grekas
force-pushed
the
dynamic-property-refs
branch
from
September 23, 2026 07:16
4fdeb56 to
fd60080
Compare
nicolas-grekas
added a commit
to symfony/polyfill
that referenced
this pull request
Sep 23, 2026
…ze()) does (nicolas-grekas) This PR was merged into the 1.x branch. Discussion ---------- [DeepClone] Preserve PHP references like unserialize(serialize()) does | Q | A | ------------- | --- | Branch? | 1.x | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | - | License | MIT Companion to symfony/php-ext-deepclone#40 and symfony/php-ext-deepclone#41, to preserve the reference topology PHP supports. References on properties, declared or dynamic, are now kept and bound back instead of being copied by value: ```php $o->b = &$o->a; $c = deepclone_from_array(deepclone_to_array($o)); $c->a = 42; // $c->b is 42 too, now ``` This also fixes references in arrays: one bound to a typed property made `deepclone_to_array()` throw a `TypeError`, unshared ones next to objects produced payloads that got rejected, that resolved object ids instead of objects, or that carried the original objects themselves, and shared ones holding `null` were rejected by `deepclone_from_array()`. Exporting objects costs about the same as before, -2% to +1% instructions depending on the graph, and importing is unchanged. The native runs of the new property tests are skipped with ext-deepclone < 0.8.4. Commits ------- 2ace422 [DeepClone] Preserve PHP references like unserialize(serialize()) does
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 #40.
To preserve the reference topology PHP supports, like
unserialize(serialize())does,deepclone_to_array()now keeps references on dynamic properties too, anddeepclone_from_array()binds them instead of rejecting such payloads since #34. The deprecation their creation raised on the origin isn't reported again; readonly classes still reject them:This also fixes the other paths that passed references to
zend_std_write_property(), which aborts debug builds: the lazy-ghost replay ofdeepclone_from_array(), anddeepclone_hydrate()withDEEPCLONE_HYDRATE_PRESERVE_REFSon dynamic properties, hooked properties and uninitialized lazy objects. Hooked properties get the value, as PHP doesn't allow references there.Companion polyfill PR: symfony/polyfill#674