Skip to content

Commit 46ca03e

Browse files
[VarExporter] Fix accessing readonly properties by reference
1 parent fc4e19b commit 46ca03e

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

src/Symfony/Component/VarExporter/Hydrator.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ public static function hydrate(object $instance, array $properties = [], array $
6161
$propertyScopes = InternalHydrator::$propertyScopes[$class] ??= InternalHydrator::getPropertyScopes($class);
6262

6363
foreach ($properties as $name => &$value) {
64-
[$scope, $name] = $propertyScopes[$name] ?? [$class, $name];
65-
$scopedProperties[$scope][$name] = &$value;
64+
[$scope, $name, $readonlyScope] = $propertyScopes[$name] ?? [$class, $name, $class];
65+
$scopedProperties[$readonlyScope ?? $scope][$name] = &$value;
6666
}
6767
unset($value);
6868
}
6969

70-
foreach ($scopedProperties as $class => $properties) {
70+
foreach ($scopedProperties as $scope => $properties) {
7171
if ($properties) {
72-
(InternalHydrator::$simpleHydrators[$class] ??= InternalHydrator::getSimpleHydrator($class))($properties, $instance);
72+
(InternalHydrator::$simpleHydrators[$scope] ??= InternalHydrator::getSimpleHydrator($scope))($properties, $instance);
7373
}
7474
}
7575

src/Symfony/Component/VarExporter/Internal/Hydrator.php

+27-9
Original file line numberDiff line numberDiff line change
@@ -155,28 +155,35 @@ public static function getHydrator($class)
155155

156156
public static function getSimpleHydrator($class)
157157
{
158-
$baseHydrator = self::$simpleHydrators['stdClass'] ??= static function ($properties, $object) {
158+
$baseHydrator = self::$simpleHydrators['stdClass'] ??= (function ($properties, $object) {
159+
$readonly = (array) $this;
160+
159161
foreach ($properties as $name => &$value) {
160-
$object->$name = &$value;
162+
$object->$name = $value;
163+
164+
if (!($readonly[$name] ?? false)) {
165+
$object->$name = &$value;
166+
}
161167
}
162-
};
168+
})->bindTo(new \stdClass());
163169

164170
switch ($class) {
165171
case 'stdClass':
166172
return $baseHydrator;
167173

168174
case 'ErrorException':
169-
return $baseHydrator->bindTo(null, new class() extends \ErrorException {
175+
return $baseHydrator->bindTo(new \stdClass(), new class() extends \ErrorException {
170176
});
171177

172178
case 'TypeError':
173-
return $baseHydrator->bindTo(null, new class() extends \Error {
179+
return $baseHydrator->bindTo(new \stdClass(), new class() extends \Error {
174180
});
175181

176182
case 'SplObjectStorage':
177183
return static function ($properties, $object) {
178184
foreach ($properties as $name => &$value) {
179185
if ("\0" !== $name) {
186+
$object->$name = $value;
180187
$object->$name = &$value;
181188
continue;
182189
}
@@ -202,14 +209,22 @@ public static function getSimpleHydrator($class)
202209
if ("\0" === $name) {
203210
$constructor($object, $value);
204211
} else {
212+
$object->$name = $value;
205213
$object->$name = &$value;
206214
}
207215
}
208216
};
209217
}
210218

211219
if (!$classReflector->isInternal()) {
212-
return $baseHydrator->bindTo(null, $class);
220+
$readonly = new \stdClass();
221+
foreach ($classReflector->getProperties(\ReflectionProperty::IS_READONLY) as $propertyReflector) {
222+
if ($class === $propertyReflector->class) {
223+
$readonly->{$propertyReflector->name} = true;
224+
}
225+
}
226+
227+
return $baseHydrator->bindTo($readonly, $class);
213228
}
214229

215230
if ($classReflector->name !== $class) {
@@ -232,6 +247,7 @@ public static function getSimpleHydrator($class)
232247
if ($setValue = $propertySetters[$name] ?? null) {
233248
$setValue($object, $value);
234249
} else {
250+
$object->$name = $value;
235251
$object->$name = &$value;
236252
}
237253
}
@@ -252,10 +268,10 @@ public static function getPropertyScopes($class)
252268
$name = $property->name;
253269

254270
if (\ReflectionProperty::IS_PRIVATE & $flags) {
255-
$propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name];
271+
$propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $class : null];
256272
continue;
257273
}
258-
$propertyScopes[$name] = [$flags & \ReflectionProperty::IS_READONLY ? $property->class : $class, $name];
274+
$propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $property->class : null];
259275

260276
if (\ReflectionProperty::IS_PROTECTED & $flags) {
261277
$propertyScopes["\0*\0$name"] = $propertyScopes[$name];
@@ -268,7 +284,9 @@ public static function getPropertyScopes($class)
268284
foreach ($r->getProperties(\ReflectionProperty::IS_PRIVATE) as $property) {
269285
if (!$property->isStatic()) {
270286
$name = $property->name;
271-
$propertyScopes["\0$class\0$name"] = [$class, $name];
287+
$readonlyScope = $property->isReadOnly() ? $class : null;
288+
$propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope];
289+
$propertyScopes[$name] ??= [$class, $name, $readonlyScope];
272290
}
273291
}
274292
}

0 commit comments

Comments
 (0)