check(); } /** * True when Xdebug 3+ is running in coverage-only mode (or empty). False * for older Xdebug without `xdebug_info` — be conservative and leave it * loaded; we can't prove the mode is safe to drop. */ private static function xdebugIsCoverageOnly(): bool { if (! function_exists('xdebug_info')) { return false; } $modes = @xdebug_info('mode'); if (! is_array($modes)) { return false; } $modes = array_values(array_filter($modes, is_string(...))); if ($modes === []) { return true; } return $modes === ['coverage']; } /** * Encodes the argv-based rules: `--tia` must be present, no coverage * flag, no forced rebuild, and TIA must be about to replay rather than * record. Plain `pest` (and anything else without `--tia`) keeps Xdebug * loaded so non-TIA users aren't surprised by behaviour changes. * * @param array $argv */ private static function runLooksDroppable(array $argv, string $projectRoot): bool { $hasTia = false; foreach ($argv as $value) { if (! is_string($value)) { continue; } if ($value === '--coverage' || str_starts_with($value, '--coverage=') || str_starts_with($value, '--coverage-')) { return false; } if ($value === '--tia-rebuild') { return false; } if ($value === '--tia') { $hasTia = true; } } if (! $hasTia) { return false; } return self::tiaWillReplay($projectRoot); } /** * True when a valid TIA graph already lives on disk AND its structural * fingerprint matches the current environment. Any other outcome * (missing graph, unreadable JSON, structural drift) means TIA will * record and the driver must stay loaded. */ private static function tiaWillReplay(string $projectRoot): bool { $path = self::graphPath($projectRoot); if (! is_file($path)) { return false; } $json = @file_get_contents($path); if ($json === false) { return false; } $graph = Graph::decode($json, $projectRoot); if (! $graph instanceof Graph) { return false; } return Fingerprint::structuralMatches( $graph->fingerprint(), Fingerprint::compute($projectRoot), ); } /** * On-disk location of the TIA graph — delegates to {@see Storage} so * the writer (TIA's bootstrapper) and this reader stay in sync * without a runtime container lookup (the container isn't booted yet * at this point). */ private static function graphPath(string $projectRoot): string { return Storage::tempDir($projectRoot).DIRECTORY_SEPARATOR.Tia::KEY_GRAPH; } }