8000 [DI] generate preload.php file for PHP 7.4 in cache folder · symfony/symfony@8aa4aca · GitHub
[go: up one dir, main page]

Skip to content

Commit 8aa4aca

Browse files
[DI] generate preload.php file for PHP 7.4 in cache folder
1 parent a0aa941 commit 8aa4aca

File tree

2 files changed

+126
-19
lines changed

2 files changed

+126
-19
lines changed

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 119 additions & 12 deletions
< 1241 td data-grid-cell-id="diff-82d7ebdd6477cecb404b0d3f100a9026e950529edb9a665460ae0330dfad7080-1251-1357-2" data-line-anchor="diff-82d7ebdd6477cecb404b0d3f100a9026e950529edb9a665460ae0330dfad7080R1357" data-selected="false" role="gridcell" style="background-color:var(--bgColor-default);padding-right:24px" tabindex="-1" valign="top" class="focusable-grid-cell diff-text-cell right-side-diff-cell left-side">
foreach ($lineage as $file) {
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class PhpDumper extends Dumper
8181
private $locatedIds = [];
8282
private $serviceLocatorTag;
8383
private $exportedVariables = [];
84+
private $baseClass;
8485

8586
/**
8687
* @var ProxyDumper
@@ -148,11 +149,11 @@ public function dump(array $options = [])
148149

149150
if (0 !== strpos($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) {
150151
$baseClass = s 10000 printf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass);
151-
$baseClassWithNamespace = $baseClass;
152+
$this->baseClass = $baseClass;
152153
} elseif ('Container' === $baseClass) {
153-
$baseClassWithNamespace = Container::class;
154+
$this->baseClass = Container::class;
154155
} else {
155-
$baseClassWithNamespace = $baseClass;
156+
$this->baseClass = $baseClass;
156157
}
157158

158159
$this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
@@ -216,7 +217,7 @@ public function dump(array $options = [])
216217
}
217218

218219
$code =
219-
$this->startClass($options['class'], $baseClass, $baseClassWithNamespace).
220+
$this->startClass($options['class'], $baseClass, $preload).
220221
$this->addServices($services).
221222
$this->addDeprecatedAliases().
222223
$this->addDefaultParametersMethod()
@@ -277,6 +278,104 @@ public function dump(array $options = [])
277278
$time = $options['build_time'];
278279
$id = hash('crc32', $hash.$time);
279280

281+
if ($preload) {
282+
$code[$options['class'].'.preload.php'] = <<<EOF
283+
<?php
284+
285+
// This file has been auto-generated by the Symfony Dependency Injection Component
286+
// You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
287+
288+
require dirname(__DIR__, 3).'/vendor/autoload.php';
289+
require __DIR__.'/Container{$hash}/{$options['class']}.php';
290+
291+
EOF;
292+
293+
$code[$options['class'].'.preload.php'] .= <<<'EOF'
294+
295+
set_error_handler(function ($t, $m, $f, $l) {
296+
if (error_reporting() & $t) {
297+
if (__FILE__ !== $f) {
298+
throw new \ErrorException($m, 0, $t, $f, $l);
299+
}
300+
301+
throw new \ReflectionException($m);
302+
}
303+
});
304+
305+
$preload = function ($class) use (&$preloaded, &$preload) {
306+
if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) {
307+
return;
308+
}
309+
310+
$preloaded[$class] = true;
311+
312+
try {
313+
$r = new \ReflectionClass($class);
314+
315+
if ($r->isInternal()) {
316+
return;
317+
}
318+
319+
$r->getConstants();
320+
$r->getDefaultProperties();
321+
322+
if (\PHP_VERSION_ID >= 70400) {
323+
foreach ($r->getProperties() as $p) {
324+
if (($t = $p->getType()) && !$t->isBuiltin()) {
325+
$preload($t->getName());
326+
}
327+
}
328+
}
329+
330+
foreach ($r->getMethods() as $m) {
331+
foreach ($m->getParameters() as $p) {
332+
if ($p->isDefaultValueAvailable() && $p->isDefaultValueConstant()) {
333+
$c = $p->getDefaultValueConstantName();
334+
335+
if ($i = strpos($c, '::')) {
336+
$preload(substr($c, 0, $i));
337+
}
338+
}
339+
340+
if (($t = $p->getType()) && !$t->isBuiltin()) {
341+
$preload($t->getName());
342+
}
343+
}
344+
345+
if (($t = $m->getReturnType()) && !$t->isBuiltin()) {
346+
$preload($t->getName());
347+
}
348+
}
349+
} catch (\ReflectionException $e) {
350+
// ignore missing classes
351+
}
352+
};
353+
354+
355+
EOF;
356+
357+
foreach ($preload as $class) {
358+
$code[$options['class'].'.preload.php'] .= sprintf("\$preload('%s');\n", $class);
359+
}
360+
361+
$code[$options['class'].'.preload.php'] .= <<<'EOF'
362+
363+
$prev = [];
364+
$classes = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
365+
366+
while ($prev !== $classes) {
367+
$prev = $classes;
368+
foreach ($classes as $c) {
369+
$preload($c);
370+
}
371+
$classes = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
372+
}
373+
374+
restore_error_handler();
375+
376+
EOF;
377+
}
378+
280379
$code[$options['class'].'.php'] = <<<EOF
281380
<?php
282381
{$namespaceLine}
@@ -399,14 +498,16 @@ private function collectLineage($class, array &$lineage)
399498
if (!$r = $this->container->getReflectionClass($class, false)) {
400499
return;
401500
}
402-
if ($this->container instanceof $class) {
501+
if (is_a($class, $this->baseClass, true)) {
403502
return;
404503
}
405504
$file = $r->getFileName();
406505
if (!$file || $this->doExport($file) === $exportedFile = $this->export($file)) {
407506
return;
408507
}
409508

509+
$lineage[$class] = substr($exportedFile, 1, -1);
510+
410511
if ($parent = $r->getParentClass()) {
411512
$this->collectLineage($parent->name, $lineage);
412513
}
@@ -419,6 +520,7 @@ private function collectLineage($class, array &$lineage)
419520
$this->collectLineage($parent->name, $lineage);
420521
}
421522

523+
unset($lineage[$class]);
422524
$lineage[$class] = substr($exportedFile, 1, -1);
423525
}
424526

@@ -474,13 +576,16 @@ private function addServiceInclude(string $cId, Definition $definition): string
474576
}
475577

476578
foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) {
579+
$file = preg_replace('#^\\$this->targetDirs\[(\d++)\]#', sprintf('\dirname(__DIR__, %d + $1)', $this->asFiles), $file);
477580
$code .= sprintf(" include_once %s;\n", $file);
478581
}
479582
}
480583

481584
foreach ($this->inlinedDefinitions as $def) {
482585
if ($file = $def->getFile()) {
483-
$code .= sprintf(" include_once %s;\n", $this->dumpValue($file));
586+
$file = $this->dumpValue($file);
587+
$file = preg_replace('#^\\$this->targetDirs\[(\d++)\]#', sprintf('\dirname(__DIR__, %d + $1)', $this->asFiles), $file);
588+
$code .= sprintf(" include_once %s;\n", $file);
484589
}
485590
}
486591

@@ -958,7 +1063,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
9581063
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
9591064
}
9601065

961-
private function startClass(string $class, string $baseClass, string $baseClassWithNamespace): string
1066+
private function startClass(string $class, string $baseClass, ?array &$preload): string
9621067
{
9631068
$namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : '';
9641069

@@ -1005,8 +1110,8 @@ public function __construct()
10051110
$code .= " \$this->containerDir = \$containerDir;\n";
10061111
}
10071112

1008-
if (Container::class !== $baseClassWithNamespace) {
1009-
$r = $this->container->getReflectionClass($baseClassWithNamespace, false);
1113+
if (Container::class !== $this->baseClass) {
1114+
$r = $this->container->getReflectionClass($this->baseClass, false);
10101115
if (null !== $r
10111116
&& (null !== $constructor = $r->getConstructor())
10121117
&& 0 === $constructor->getNumberOfRequiredParameters()
@@ -1026,7 +1131,7 @@ public function __construct()
10261131
$code .= $this->addMethodMap();
10271132
$code .= $this->asFiles ? $this->addFileMap() : '';
10281133
$code .= $this->addAliases();
1029-
$code .= $this->addInlineRequires();
1134+
$code .= $this->addInlineRequires($preload);
10301135
$code .= <<<EOF
10311136
}
10321137
@@ -1227,7 +1332,7 @@ protected function {$methodNameAlias}()
12271332
return $code;
12281333
}
12291334

1230-
private function addInlineRequires(): string
1335+
private function addInlineRequires(?array &$preload): string
12311336
{
12321337
if (!$this->hotPathTag || !$this->inlineRequires) {
12331338
return '';
@@ -1241,6 +1346,7 @@ private function addInlineRequires(): string
12411346

12421347
foreach ($inlinedDefinitions as $def) {
12431348
if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
1349+
$preload[$class] = $class;
12441350
$this->collectLineage($class, $lineage);
12451351
}
12461352
}
@@ -1251,11 +1357,12 @@ private function addInlineRequires(): string
12511357
12521358
if (!isset($this->inlinedRequires[$file])) {
12531359
$this->inlinedRequires[$file] = true;
1360+
$file = preg_replace('#^\\$this->targetDirs\[(\d++)\]#', sprintf('\dirname(__DIR__, %d + $1)', $this->asFiles), $file);
12541361
$code .= sprintf("\n include_once %s;", $file);
12551362
}
12561363
}
12571364

1258-
return $code ? sprintf("\n \$this->privates['service_container'] = function () {%s\n };\n", $code) : '';
1365+
return $code ? sprintf("\n \$this->privates['service_container'] = static function () {%s\n };\n", $code) : '';
12591366
}
12601367

12611368
private function addDefaultParametersMethod(): string

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public function __construct()
3636

3737
$this->aliases = [];
3838

39-
$this->privates['service_container'] = function () {
40-
include_once $this->targetDirs[1].'/includes/HotPath/I1.php';
41-
include_once $this->targetDirs[1].'/includes/HotPath/P1.php';
42-
include_once $this->targetDirs[1].'/includes/HotPath/T1.php';
43-
include_once $this->targetDirs[1].'/includes/HotPath/C1.php';
39+
$this->privates['service_container'] = static function () {
40+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/I1.php';
41+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/P1.php';
42+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/T1.php';
43+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/C1.php';
4444
};
4545
}
4646

@@ -90,8 +90,8 @@ protected function getC1Service()
9090
*/
9191
protected function getC2Service()
9292
{
93-
include_once $this->targetDirs[1].'/includes/HotPath/C2.php';
94-
include_once $this->targetDirs[1].'/includes/HotPath/C3.php';
93+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/C2.php';
94+
include_once \dirname(__DIR__, 0 + 1).'/includes/HotPath/C3.php';
9595

9696
return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C2'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2(new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3());
9797
}

0 commit comments

Comments
 (0)
0