Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit798ba60

Browse files
[VarExporter] Add trait to help implement lazy loading ghost objects
1 parentbbf25d6 commit798ba60

File tree

14 files changed

+994
-24
lines changed

14 files changed

+994
-24
lines changed

‎src/Symfony/Component/VarExporter/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
6.2
55
---
66

7+
* Add`LazyGhostObjectTrait`
78
* Add`Hydrator::hydrate()`
89
* Preserve PHP references also when using`Hydrator::hydrate()` or`Instantiator::instantiate()`
910
* Add support for hydrating from native (array) casts

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

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

6363
foreach ($propertiesas$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
}
67-
unset($value);
6867
}
6968

70-
foreach ($scopedPropertiesas$class =>$properties) {
69+
foreach ($scopedPropertiesas$scope =>$properties) {
7170
if ($properties) {
72-
(InternalHydrator::$simpleHydrators[$class] ??= InternalHydrator::getSimpleHydrator($class))($properties,$instance);
71+
(InternalHydrator::$simpleHydrators[$scope] ??= InternalHydrator::getSimpleHydrator($scope))($properties,$instance);
7372
}
7473
}
7574

‎src/Symfony/Component/VarExporter/Instantiator.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ public static function instantiate(string $class, array $properties = [], array
5454
$instance =unserialize('O:'.\strlen($class).':"'.$class.'":0:{}');
5555
}
5656

57-
return Hydrator::hydrate($instance,$properties,$scopedProperties);
57+
return$properties ||$scopedProperties ?Hydrator::hydrate($instance,$properties,$scopedProperties) :$instance;
5858
}
5959
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\VarExporter\Internal;
13+
14+
/**
15+
* @internal
16+
*/
17+
enum EmptyScope
18+
{
19+
}

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,28 +155,35 @@ public static function getHydrator($class)
155155

156156
publicstaticfunctiongetSimpleHydrator($class)
157157
{
158-
$baseHydrator =self::$simpleHydrators['stdClass'] ??=staticfunction ($properties,$object) {
158+
$baseHydrator =self::$simpleHydrators['stdClass'] ??= (function ($properties,$object) {
159+
$readonly = (array)$this;
160+
159161
foreach ($propertiesas$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,newclass()extends \ErrorException {
175+
return$baseHydrator->bindTo(new \stdClass(),newclass()extends \ErrorException {
170176
});
171177

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

176182
case'SplObjectStorage':
177183
returnstaticfunction ($properties,$object) {
178184
foreach ($propertiesas$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
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\VarExporter\Internal;
13+
14+
useSymfony\Component\VarExporter\HydratorasPublicHydrator;
15+
16+
/**
17+
* Stores the state of lazy ghost objects and caches related reflection information.
18+
*
19+
* As a micro-optimization, this classes uses no type-hints.
20+
*
21+
* @internal
22+
*/
23+
class LazyGhostObjectRegistry
24+
{
25+
/**
26+
* @var array<class-string, \ReflectionClass>
27+
*/
28+
publicstatic$classReflectors = [];
29+
30+
/**
31+
* @var array<class-string, array<string, mixed>>
32+
*/
33+
publicstatic$defaultProperties = [];
34+
35+
/**
36+
* @var array<int, \Closure>
37+
*/
38+
publicstatic$initializers = [];
39+
40+
/**
41+
* @var array<class-string, list<\Closure>>
42+
*/
43+
publicstatic$classResetters = [];
44+
45+
/**
46+
* @var array<int, array<string, array<string, true>>>
47+
*/
48+
publicstatic$unsetProperties = [];
49+
50+
/**
51+
* @var array<int, int>
52+
*/
53+
publicstatic$states = [];
54+
55+
/**
56+
* @var array<class-string, array{get: \Closure, set: \Closure, isset: \Closure, unset: \Closure}>
57+
*/
58+
publicstatic$classAccessors = [];
59+
60+
/**
61+
* @var array<class-string, array{get: int, set: bool, isset: bool, unset: bool, clone: bool, serialize: bool, sleep: bool, destruct: bool}>
62+
*/
63+
publicstatic$parentMethods = [];
64+
65+
publicstaticfunctiongetClassResetters($class)
66+
{
67+
$classProperties = [];
68+
foreach (Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class)as$key => [$scope,$name,$readonlyScope]) {
69+
if ('lazyGhostObjectId' !==$name) {
70+
$classProperties[$readonlyScope ??$scope][$name] =$key;
71+
}
72+
}
73+
74+
$resetters = [];
75+
foreach ($classPropertiesas$scope =>$properties) {
76+
$resetters[] = \Closure::bind(staticfunction ($instance)use ($properties) {
77+
foreach ($propertiesas$name =>$key) {
78+
unset($instance->$name);
79+
}
80+
},null,$scope);
81+
}
82+
83+
$resetters[] =staticfunction ($instance) {
84+
foreach ((array)$instanceas$name =>$value) {
85+
if ("\0" !== ($name[0] ??'')) {
86+
unset($instance->$name);
87+
}
88+
}
89+
};
90+
91+
return$resetters;
92+
}
93+
94+
publicstaticfunctiongetClassAccessors($class)
95+
{
96+
return \Closure::bind(staticfunction () {
97+
return [
98+
'get' =>staticfunction &($instance,$name,$readonly) {
99+
if (!$readonly) {
100+
return$instance->$name;
101+
}
102+
$value =$instance->$name;
103+
104+
return$value;
105+
},
106+
'set' =>staticfunction ($instance,$name,$value) {
107+
$instance->$name =$value;
108+
},
109+
'isset' =>staticfunction ($instance,$name) {
110+
returnisset($instance->$name);
111+
},
112+
'unset' =>staticfunction ($instance,$name) {
113+
unset($instance->$name);
114+
},
115+
];
116+
},null,$class)();
117+
}
118+
119+
publicstaticfunctiongetParentMethods($class)
120+
{
121+
$parent =get_parent_class($class);
122+
123+
return [
124+
'get' =>$parent &&method_exists($parent,'__get') ? ((new \ReflectionMethod($parent,'__get'))->returnsReference() ?2 :1) :0,
125+
'set' =>$parent &&method_exists($parent,'__set'),
126+
'isset' =>$parent &&method_exists($parent,'__isset'),
127+
'unset' =>$parent &&method_exists($parent,'__unset'),
128+
'clone' =>$parent &&method_exists($parent,'__clone'),
129+
'serialize' =>$parent &&method_exists($parent,'__serialize'),
130+
'sleep' =>$parent &&method_exists($parent,'__sleep'),
131+
'destruct' =>$parent &&method_exists($parent,'__destruct'),
132+
];
133+
}
134+
135+
publicstaticfunctioninitialize($instance,$id,$propertyName,$propertyScope)
136+
{
137+
$class =\get_class($instance);
138+
139+
if (0 >$state =self::$states[$id] ??=1 < (new \ReflectionFunction(self::$initializers[$id]))->getNumberOfRequiredParameters() ?0 :1) {
140+
returntrue;
141+
}
142+
143+
if ($state = -$state) {
144+
if ($defaultProperties =array_diff_key(self::$defaultProperties[$class], (array)$instance)) {
145+
PublicHydrator::hydrate($instance,$defaultProperties);
146+
}
147+
148+
self::$initializers[$id]($instance);
149+
150+
returntrue;
151+
}
152+
153+
$value =self::$initializers[$id](...[$instance,$propertyName,$propertyScope]);
154+
155+
$propertyScope ??=$class;
156+
$accessor =self::$classAccessors[$propertyScope] ??=self::getClassAccessors($propertyScope);
157+
158+
$accessor['set']($instance,$propertyName,$value);
159+
160+
returnfalse;
161+
}
162+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\VarExporter;
13+
14+
interface LazyGhostObjectInterface
15+
{
16+
/**
17+
* @param \Closure(static):void|\Closure(static, string, ?string):mixed $initializer Initializes the instance passed as argument; when partial initialization
18+
* is desired the closure should take extra arguments $propertyName and
19+
* $propertyScope and should return the value of the corresponding property
20+
*/
21+
publicstaticfunctioncreateLazyGhostObject(\Closure$initializer):static;
22+
23+
/**
24+
* Forces initialization of a lazy ghost object.
25+
*/
26+
publicfunctioninitializeLazyGhostObject():void;
27+
28+
/**
29+
* @return bool Returns false when the object cannot be reset, ie when it's not a ghost object
30+
*/
31+
publicfunctionresetLazyGhostObject():bool;
32+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp