Namespace PHPStan\Turbo

Classes
TurboExtensionEnabler

Activates the phpstan_turbo extension's shadowing classes. The extension registers nothing under PHPStan's class names at module startup. Once the Composer autoloader is registered, activateIfCompatible() checks the loaded extension's version against EXPECTED_EXTENSION_VERSION and, when it matches, asks Runtime::activateShadowing() to declare the native classes under the PHP twins' real names — PHPStan\TrinaryLogic then is the native class, linked like a PHP declaration (parents and interfaces resolved through the autoloader). A mismatched or absent extension never gets the call, and the PHP implementations load as usual. The version is the short SHA of the last commit touching turbo-ext/src/, enforced by the phar.yml turbo-version job; the native classes must behave exactly like the PHP implementations, hence the gate.

TurboProcessRestarter

Restarts the main PHPStan process via pcntl_exec() when the process it was started as is not the one PHPStan wants to run — for either of two reasons, checked independently. The distributed turbo extension is available but not loaded. Parallel analysis prefers pcntl_fork()ed workers over spawned ones (see ForkParallelChecker) — a forked worker inherits the booted process instead of paying a full re-boot. But a forked worker also inherits the parent's loaded extensions: the spawn-time -d extension= injection (ProcessHelper) cannot reach it, and dl() cannot load a binary from next to the phar. So the whole process is re-executed with the extension before anything else runs — forked workers then inherit the extension, its shadowing classes, and (when running from a phar) the phar-fork-guard that keeps phar:// reads safe across fork. The OPcache configuration in effect is not the one PHPStan wants (see resolveOpcacheArgs()) — usually because OPcache is dormant on CLI, or has JIT on. The restarted process runs with it activated, JIT pinned off, and forked workers share the parent's warm opcode cache. This reason stands on its own so that a php.ini which already loads turbo (a source checkout with a locally built extension, say) does not leave OPcache dormant just because there is no extension left to restart for. The restart carries two marker ini entries: RESTARTED_INI is the retry stop (a binary that failed to load, or an OPcache that could not start, would otherwise restart forever), and EXTENSION_PATH_INI tells TurboExtensionSelector that spawned workers still need the -d flag (command-line -d flags, unlike php.ini, are not inherited). ProcessHelper sets both on the workers it spawns, along with the OPcache entries: a worker's configuration is decided by the process spawning it, so it never restarts itself — before that, every spawned worker on a pcntl host re-executed itself once to activate OPcache, rebuilding its command line without the sys_temp_dir and extension entries of the spawn.