8000 [VarExporter] optimize dumped code in time and space · symfony/symfony@3caf702 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3caf702

Browse files
[VarExporter] optimize dumped code in time and space
1 parent a1aee05 commit 3caf702

19 files changed

+184
-133
lines changed

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@ public function __construct(?Registry $registry, ?Values $values, array $propert
3535
$this->wakeups = $wakeups;
3636
}
3737

38-
public static function pop($objects, $values, $properties, $value, $wakeups)
38+
public static function pop($_, $objects, $values, $properties, $value, $wakeups)
3939
{
40-
list(Registry::$objects, Registry::$references) = \array_pop(Registry::$stack);
41-
4240
foreach ($properties as $class => $vars) {
4341
(self::$configurators[$class] ?? self::getConfigurator($class))($vars, $objects);
4442
}
@@ -99,15 +97,33 @@ public static function getConfigurator($class)
9997
};
10098
}
10199

100+
$privateProperties = 0;
102101
$propertyReflectors = array();
103102
foreach ($classReflector->getProperties(\ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE) as $propertyReflector) {
104103
if (!$propertyReflector->isStatic()) {
105104
$propertyReflector->setAccessible(true);
106105
$propertyReflectors[$propertyReflector->name] = $propertyReflector;
106+
$privateProperties += $propertyReflector->isPrivate();
107107
}
108108
}
109109

110-
return self::$configurators[$class] = static function ($properties, $objects) use ($propertyReflectors) {
110+
if (!$propertyReflectors || !($privateProperties || $classReflector->isFinal())) {
111+
self::$configurators[$class] = static function ($properties, $objects) {
112+
foreach ($properties as $name => $values) {
113+
foreach ($values as $i => $v) {
114+
$objects[$i]->$name = $v;
115+
}
116+
}
117+
};
118+
119+
if ($propertyReflectors) {
120+
self::$configurators[$class] = \Closure::bind(self::$configurators[$class], null, eval('return new class() extends '.$class.'{};'));
121+
}
122+
123+
return self::$configurators[$class];
124+
}
125+
126+
self::$configurators[$class] = static function ($properties, $objects) use (&$propertyReflectors) {
111127
foreach ($properties as $name => $values) {
112128
if (isset($propertyReflectors[$name])) {
113129
foreach ($values as $i => $v) {
@@ -120,5 +136,17 @@ public static function getConfigurator($class)
120136
}
121137
}
122138
};
139+
140+
if (\count($propertyReflectors) !== $privateProperties && !$classReflector->isFinal()) {
141+
foreach ($propertyReflectors as $propertyReflector) {
142+
if ($propertyReflector->isProtected()) {
143+
unset($propertyReflectors[$propertyReflector->name]);
144+
}
145+
}
146+
147+
self::$configurators[$class] = \Closure::bind(self::$configurators[$class], null, eval('return new class() extends '.$class.'{};'));
148+
}
149+
150+
return self::$configurators[$class];
123151
}
124152
}

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

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
4848
$refs[$k] = $value = $values[$k];
4949
if ($value instanceof Reference && 0 > $value->id) {
5050
$valuesAreStatic = false;
51+
++$value->count;
5152
continue;
5253
}
5354
$refsPool[] = array(&$refs[$k], $value, &$value);
54-
$refs[$k] = $values[$k] = new Reference(-\count($refsPool));
55+
$refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
5556
}
5657

5758
if (\is_array($value)) {
@@ -173,11 +174,14 @@ public static function export($value, $indent = '')
173174

174175
if ($value instanceof Reference) {
175176
if (0 <= $value->id) {
176-
return '\\'.Registry::class.'::$objects['.$value->id.']';
177+
return '$o['.$value->id.']';
178+
}
179+
if (!$value->count) {
180+
return self::export($value->value, $indent);
177181
}
178182
$value = -$value->id;
179183

180-
return '&\\'.Registry::class.'::$references['.$value.']';
184+
return '&$r['.$value.']';
181185
}
182186
$subIndent = $indent.' ';
183187

@@ -224,9 +228,9 @@ public static function export($value, $indent = '')
224228
}
225229

226230
if ($value instanceof Values) {
227-
$code = '';
231+
$code = $subIndent."\$r = [],\n";
228232
foreach ($value->values as $k => $v) {
229-
$code .= $subIndent.'\\'.Registry::class.'::$references['.$k.'] = '.self::export($v, $subIndent).",\n";
233+
$code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n";
230234
}
231235

232236
return "[\n".$code.$indent.']';
@@ -236,36 +240,47 @@ public static function export($value, $indent = '')
236240
$code = '';
237241
$reflectors = array();
238242
$serializables = array();
243+
$seen = array();
244+
$prototypesAccess = '($p =& $r::$prototypes)';
245+
$factoriesAccess = '($f =& $r::$factories)';
239246

240247
foreach ($value as $k => $class) {
241248
if (':' === ($class[1] ?? null)) {
242249
$serializables[$k] = $class;
243250
continue;
244251
}
245252
$c = '\\'.$class.'::class';
246-
$reflectors[$class] = '\\'.Registry::class.'::$reflectors['.$c.'] ?? \\'.Registry::class.'::getClassReflector('.$c.', '
247-
.self::export(Registry::$instantiableWithoutConstructor[$class]).', '
248-
.self::export(Registry::$cloneable[$class])
249-
.')';
250-
251-
if (Registry::$cloneable[$class]) {
252-
$code .= $subIndent.'clone \\'.Registry::class.'::$prototypes['.$c."],\n";
253-
} elseif (Registry::$instantiableWithoutConstructor[$class]) {
254-
$code .= $subIndent.'\\'.Registry::class.'::$reflectors['.$c."]->newInstanceWithoutConstructor(),\n";
253+
if ($seen[$class] ?? false) {
254+
if (Registry::$cloneable[$class]) {
255+
$code .= $subIndent.'clone $p['.$c."],\n";
256+
} else {
257+
$code .= $subIndent.'$f['.$c."](),\n";
258+
}
255259
} else {
256-
$code .= $subIndent.'\\'.Registry::class.'::$reflectors['.$c."]->newInstance(),\n";
260+
$instantiableWithoutConstructor = self::export(Registry::$instantiableWithoutConstructor[$class]);
261+
262+
if (Registry::$cloneable[$class]) {
263+
$code .= $subIndent.'clone ('.$prototypesAccess.'['.$c.'] ?? $r::p('.$c.', '.$instantiableWithoutConstructor.")),\n";
264+
$prototypesAccess = '$p';
265+
} else {
266+
$code .= $subIndent.'('.$factoriesAccess.'['.$c.'] ?? $r::f('.$c.', '.$instantiableWithoutConstructor.'))()'.",\n";
267+
$factoriesAccess = '$f';
268+
}
269+
$seen[$class] = true;
257270
}
258271
}
259272

260-
if ($reflectors) {
261-
$code = "[\n".$subIndent.implode(",\n".$subIndent, $reflectors).",\n".$indent."], [\n".$code.$indent.'], ';
262-
$code .= !$serializables ? "[\n".$indent.']' : self::export($serializables, $indent);
273+
if ('' !== $code) {
274+
$code = "\n".$code.$indent;
275+
}
276+
277+
if ($serializables) {
278+
$code = '$r::unserialize(['.$code.'], '.self::export($serializables, $indent).')';
263279
} else {
264-
$code = '[], []';
265-
$code .= ', '.self::export($serializables, $indent);
280+
$code = '['.$code.']';
266281
}
267282

268-
return '\\'.Registry::class.'::push('.$code.')';
283+
return '$o = '.$code;
269284
}
270285

271286
if ($value instanceof Configurator) {
@@ -275,6 +290,7 @@ public static function export($value, $indent = '')
275290
}
276291

277292
$code = array(
293+
'$r = \\'.Registry::class.'::class',
278294
self::export($value->registry, $subIndent),
279295
self::export($value->values, $subIndent),
280296
'' !== $code ? "[\n".$code.$subIndent.']' : '[]',

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
class Reference
2020
{
2121
public $id;
22+
public $value;
23+
public $count = 0;
2224

23-
public function __construct(int $id)
25+
public function __construct(int $id, $value = null)
2426
{
2527
$this->id = $id;
28+
$this->value = $value;
2629
}
2730
}

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
*/
1919
class Registry
2020
{
21-
public static $stack = array();
22-
public static $objects = array();
23-
public static $references = array();
2421
public static $reflectors = array();
2522
public static $prototypes = array();
23+
public static $factories = array();
2624
public static $cloneable = array();
2725
public static $instantiableWithoutConstructor = array();
2826

@@ -33,28 +31,33 @@ public function __construct(array $classes)
3331
}
3432
}
3533

36-
public static function push($reflectors, $objects, $serializables)
34+
public static function unserialize($objects, $serializables)
3735
{
38-
self::$stack[] = array(self::$objects, self::$references);
39-
self::$references = array();
40-
41-
if (!$serializables) {
42-
return self::$objects = $objects;
43-
}
4436
$unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
4537

4638
try {
4739
foreach ($serializables as $k => $v) {
4840
$objects[$k] = unserialize($v);
4941
}
50-
} catch (\Throwable $e) {
51-
list(self::$objects, self::$references) = array_pop(self::$stack);
52-
throw $e;
5342
} finally {
5443
ini_set('unserialize_callback_func', $unserializeCallback);
5544
}
5645

57-
return self::$objects = $objects;
46+
return $objects;
47+
}
48+
49+
public static function p($class, $instantiableWithoutConstructor)
50+
{
51+
self::getClassReflector($class, $instantiableWithoutConstructor, true);
52+
53+
return self::$prototypes[$class];
54+
}
55+
56+
public static function f($class, $instantiableWithoutConstructor)
57+
{
58+
$reflector = self::$reflectors[$class] ?? self::getClassReflector($class, $instantiableWithoutConstructor, false);
59+
60+
return self::$factories[$class] = \Closure::fromCallable(array($reflector, $instantiableWithoutConstructor ? 'newInstanceWithoutConstructor' : 'newInstance'));
5861
}
5962

6063
public static function getClassReflector($class, $instantiableWithoutConstructor = null, $cloneable = null)
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<?php
22

33
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
4-
\Symfony\Component\VarExporter\Internal\Registry::push([
5-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\ArrayIterator::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\ArrayIterator::class, true, true),
6-
], [
7-
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayIterator::class],
8-
], [
9-
]),
4+
$r = \Symfony\Component\VarExporter\Internal\Registry::class,
5+
$o = [
6+
clone (($p =& $r::$prototypes)[\ArrayIterator::class] ?? $r::p(\ArrayIterator::class, true)),
7+
],
108
null,
119
[
1210
\ArrayIterator::class => [
@@ -20,6 +18,6 @@
2018
],
2119
],
2220
],
23-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
21+
$o[0],
2422
[]
2523
);
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<?php
22

33
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
4-
\Symfony\Component\VarExporter\Internal\Registry::push([
5-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyArrayObject::class, true, true),
6-
], [
7-
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\Symfony\Component\VarExporter\Tests\MyArrayObject::class],
8-
], [
9-
]),
4+
$r = \Symfony\Component\VarExporter\Internal\Registry::class,
5+
$o = [
6+
clone (($p =& $r::$prototypes)[\Symfony\Component\VarExporter\Tests\MyArrayObject::class] ?? $r::p(\Symfony\Component\VarExporter\Tests\MyArrayObject::class, true)),
7+
],
108
null,
119
[
1210
\ArrayObject::class => [
@@ -20,6 +18,6 @@
2018
],
2119
],
2220
],
23-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
21+
$o[0],
2422
[]
2523
);
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
<?php
22

33
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
4-
\Symfony\Component\VarExporter\Internal\Registry::push([
5-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\ArrayObject::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\ArrayObject::class, true, true),
6-
], [
7-
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayObject::class],
8-
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\ArrayObject::class],
9-
], [
10-
]),
4+
$r = \Symfony\Component\VarExporter\Internal\Registry::class,
5+
$o = [
6+
clone (($p =& $r::$prototypes)[\ArrayObject::class] ?? $r::p(\ArrayObject::class, true)),
7+
clone $p[\ArrayObject::class],
8+
],
119
null,
1210
[
1311
\ArrayObject::class => [
1412
"\0" => [
1513
[
1614
[
1715
1,
18-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
16+
$o[0],
1917
],
2018
0,
2119
],
2220
],
2321
'foo' => [
24-
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
22+
$o[1],
2523
],
2624
],
2725
],
28-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
26+
$o[0],
2927
[]
3028
);
Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
<?php
22

33
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
4-
\Symfony\Component\VarExporter\Internal\Registry::push([
5-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyCloneable::class, true, false),
6-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\Symfony\Component\VarExporter\Tests\MyNotCloneable::class, true, false),
7-
], [
8-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyCloneable::class]->newInstanceWithoutConstructor(),
9-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class]->newInstanceWithoutConstructor(),
10-
], [
11-
]),
4+
$r = \Symfony\Component\VarExporter\Internal\Registry::class,
5+
$o = [
6+
(($f =& $r::$factories)[\Symfony\Component\VarExporter\Tests\MyCloneable::class] ?? $r::f(\Symfony\Component\VarExporter\Tests\MyCloneable::class, true))(),
7+
($f[\Symfony\Component\VarExporter\Tests\MyNotCloneable::class] ?? $r::f(\Symfony\Component\VarExporter\Tests\MyNotCloneable::class, true))(),
8+
],
129
null,
1310
[],
1411
[
15-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
16-
\Symfony\Component\VarExporter\Internal\Registry::$objects[1],
12+
$o[0],
13+
$o[1],
1714
],
1815
[]
1916
);

src/Symfony/Component/VarExporter/Tests/Fixtures/datetime.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<?php
22

33
return \Symfony\Component\VarExporter\Internal\Configurator::pop(
4-
\Symfony\Component\VarExporter\Internal\Registry::push([
5-
\Symfony\Component\VarExporter\Internal\Registry::$reflectors[\DateTime::class] ?? \Symfony\Component\VarExporter\Internal\Registry::getClassReflector(\DateTime::class, true, true),
6-
], [
7-
clone \Symfony\Component\VarExporter\Internal\Registry::$prototypes[\DateTime::class],
8-
], [
9-
]),
4+
$r = \Symfony\Component\VarExporter\Internal\Registry::class,
5+
$o = [
6+
clone (($p =& $r::$prototypes)[\DateTime::class] ?? $r::p(\DateTime::class, true)),
7+
],
108
null,
119
[
1210
\DateTime::class => [
@@ -21,7 +19,7 @@
2119
],
2220
],
2321
],
24-
\Symfony\Component\VarExporter\Internal\Registry::$objects[0],
22+
$o[0],
2523
[
2624
1 => 0,
2725
]

0 commit comments

Comments
 (0)
0