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
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 = sprintf('%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
foreach ($lineage as $file) {
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy