You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[DeepClone] Match unserialize() permissiveness on scoped-mode prop names
Mirrors symfony/php-ext-deepclone#12 follow-up commit.
In scoped mode, the pre-v0.4.0 hot-path validation rejected non-string
keys, NUL-containing names, and mangled-shape keys with a ValueError.
That was stricter than what unserialize() does on the same shapes in an
O:… payload — unserialize() coerces integer keys, stores NUL-in-middle
names as raw dynamic properties, and lets the engine's native Error
surface for NUL-prefix names.
- Removed the per-prop `!\is_string($name) || str_contains($name, "\0")`
check from all eight hydrator closures (stdClass + 3 variants × 2
ref-modes).
- Dropped the now-unused `DeepClone::throwInvalidPropName()` helper.
- Updated and renamed the corresponding tests.
Besides semantic alignment with unserialize(), this saves ~18 ns per
property in the hot path — on a 5-prop stdClass hydration that's ~130 ns
(~18% of the call), matching what the ext-side commit also avoids.
@@ -444,7 +447,7 @@ public static function deepclone_hydrate(object|string $object_or_class, array $
444
447
$scopeName = substr($name, 1, $sep - 1);
445
448
$realName = substr($name, $sep + 1);
446
449
447
-
if (\str_contains($realName, "\0")) {
450
+
if (str_contains($realName, "\0")) {
448
451
thrownew \ValueError('deepclone_hydrate(): Argument #2 ($vars) in MANGLED_VARS mode contains an invalid mangled key');
449
452
}
450
453
@@ -491,7 +494,10 @@ public static function deepclone_hydrate(object|string $object_or_class, array $
491
494
$hasRefs = false;
492
495
if ($flags & \DEEPCLONE_HYDRATE_PRESERVE_REFS) {
493
496
foreach ($propertiesas$k => $_) {
494
-
if (\ReflectionReference::fromArrayElement($properties, $k)) { $hasRefs = true; break; }
497
+
if (\ReflectionReference::fromArrayElement($properties, $k)) {
498
+
$hasRefs = true;
499
+
break;
500
+
}
495
501
}
496
502
}
497
503
@@ -510,20 +516,6 @@ public static function deepclone_hydrate(object|string $object_or_class, array $
510
516
return$object;
511
517
}
512
518
513
-
/**
514
-
* @internal
515
-
*
516
-
* Cold path invoked from the generated hydrator closures to report a
517
-
* property name that is not a string or contains a NUL byte.
518
-
*/
519
-
publicstaticfunctionthrowInvalidPropName(mixed$name, string$scope): never
520
-
{
521
-
if (!\is_string($name)) {
522
-
thrownew \ValueError(\sprintf('deepclone_hydrate(): Argument #2 ($vars) scope "%s" must have only string keys', $scope));
523
-
}
524
-
thrownew \ValueError(\sprintf('deepclone_hydrate(): Argument #2 ($vars) scope "%s" contains an invalid property name; use bare property names in scoped mode, or pass DEEPCLONE_HYDRATE_MANGLED_VARS in $flags', $scope));
525
-
}
526
-
527
519
/**
528
520
* Returns a type name matching zend_zval_value_name() output for
529
521
* error messages compatible with the C extension.
@@ -1357,17 +1349,11 @@ private static function getSimpleHydrator(string $class, int $flags = 0): \Closu
0 commit comments