Repository navigation
Expand file tree
/
Copy pathBootstrapFilesRunner.php
More file actions
97 lines (82 loc) · 3.08 KB
/
Copy pathBootstrapFilesRunner.php
File metadata and controls
97 lines (82 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php declare(strict_types = 1);
namespace PHPStan\Command;
use PHPStan\DependencyInjection\AutowiredService;
use PHPStan\DependencyInjection\Container;
use PHPStan\Reflection\BetterReflection\SourceLocator\BootstrapAutoloaderExceptionReporter;
use function spl_autoload_functions;
/**
* Executes the configured bootstrapFiles, once per process.
*
* The analyse flow calls run() at exactly the places that need the files
* executed - resources they open (an objectManagerLoader's database
* connection, a query reflector's PDO) must not be inherited by forked
* children:
*
* - the main thread right before an in-process analysis (AnalyserRunner),
* - every worker, spawned or forked (WorkerRunner),
* - the main thread after the workers of a parallel analysis
* (AnalyserRunner), and after a fully cached run (AnalyseApplication) -
* before the phases that may reflect analysed code.
*
* Every other command runs them eagerly in CommandHelper::begin(). The
* once-per-process latch exists for a worker forked from a parent that
* already ran the files (the fixer flow runs them eagerly before its
* repeated analysis rounds): such a worker inherits that execution and
* run() must not repeat it.
*/
#[AutowiredService]
final class BootstrapFilesRunner
{
private bool $hasRun = false;
public function __construct(
private Container $container,
private BootstrapAutoloaderExceptionReporter $bootstrapAutoloaderExceptionReporter,
)
{
}
/**
* @throws InceptionNotSuccessfulException
*/
public function run(Output $errorOutput, bool $debugEnabled): void
{
if ($debugEnabled) {
$this->bootstrapAutoloaderExceptionReporter->enable($errorOutput);
}
if ($this->hasRun) {
return;
}
$this->hasRun = true;
/** @var list<callable(string): void>|false $autoloadFunctionsBefore */
$autoloadFunctionsBefore = spl_autoload_functions();
foreach ($this->container->getParameter('bootstrapFiles') as $bootstrapFile) {
CommandHelper::executeBootstrapFile($bootstrapFile, $this->container, $errorOutput, $debugEnabled);
}
self::mergeNewAutoloadFunctions($autoloadFunctionsBefore);
}
/**
* Merges autoloaders registered since $autoloadFunctionsBefore into the
* global the BetterReflection source locators consult lazily (see
* autoloadFunctions.php) - late merging in a deferred or forked run is
* picked up by the next reflection ask.
*
* @param list<callable(string): void>|false $autoloadFunctionsBefore
*/
public static function mergeNewAutoloadFunctions(array|false $autoloadFunctionsBefore): void
{
/** @var list<callable(string): void>|false $autoloadFunctionsAfter */
$autoloadFunctionsAfter = spl_autoload_functions();
if ($autoloadFunctionsBefore === false || $autoloadFunctionsAfter === false) {
return;
}
$newAutoloadFunctions = $GLOBALS['__phpstanAutoloadFunctions'] ?? [];
foreach ($autoloadFunctionsAfter as $after) {
foreach ($autoloadFunctionsBefore as $before) {
if ($after === $before) {
continue 2;
}
}
$newAutoloadFunctions[] = $after;
}
$GLOBALS['__phpstanAutoloadFunctions'] = $newAutoloadFunctions;
}
}