loadStackTraceInfo(); } public static function bindBuildPHPExtraInfo(array $indent_texts): void { self::$build_php_extra_info = $indent_texts; } public function bindExtensionInfo(array $extension_info): void { $this->extension_info = $extension_info; } public function addExtraLogFile(string $key, string $filename): void { $this->extra_log_files[$key] = $filename; } public function getBuildPHPExtraInfo(): ?array { return self::$build_php_extra_info; } /** * Returns an array containing information about the SPC module. * * This method can be overridden by subclasses to provide specific module information. * * @return null|array{ * library_name: string, * library_class: string, * os: string, * file: null|string, * line: null|int, * } an array containing module information */ public function getLibraryInfo(): ?array { return $this->library_info; } /** * Returns an array containing information about the PHP build process. * * @return null|array{ * builder_class: string, * os: string, * file: null|string, * line: null|int, * } an array containing PHP build information */ public function getBuildPHPInfo(): ?array { return $this->build_php_info; } /** * Returns an array containing information about the SPC extension. * * This method can be overridden by subclasses to provide specific extension information. * * @return null|array{ * extension_name: string, * extension_class: string, * file: null|string, * line: null|int, * } an array containing extension information */ public function getExtensionInfo(): ?array { return $this->extension_info; } public function getExtraLogFiles(): array { return $this->extra_log_files; } private function loadStackTraceInfo(): void { $trace = $this->getTrace(); foreach ($trace as $frame) { if (!isset($frame['class'])) { continue; } // Check if the class is a subclass of LibraryBase if (!$this->library_info && is_subclass_of($frame['class'], LibraryBase::class)) { try { $reflection = new \ReflectionClass($frame['class']); if ($reflection->hasConstant('NAME')) { $name = $reflection->getConstant('NAME'); if ($name !== 'unknown') { $this->library_info = [ 'library_name' => $name, 'library_class' => $frame['class'], 'os' => match (true) { is_a($frame['class'], BSDLibraryBase::class, true) => 'BSD', is_a($frame['class'], LinuxLibraryBase::class, true) => 'Linux', is_a($frame['class'], MacOSLibraryBase::class, true) => 'macOS', is_a($frame['class'], WindowsLibraryBase::class, true) => 'Windows', default => 'Unknown', }, 'file' => $frame['file'] ?? null, 'line' => $frame['line'] ?? null, ]; continue; } } } catch (\ReflectionException) { continue; } } // Check if the class is a subclass of BuilderBase and the method is buildPHP if (!$this->build_php_info && is_subclass_of($frame['class'], BuilderBase::class) && $frame['function'] === 'buildPHP') { $reflection = new \ReflectionClass($frame['class']); if ($reflection->hasProperty('options')) { $options = $reflection->getProperty('options')->getValue(); } $this->build_php_info = [ 'builder_class' => $frame['class'], 'builder_options' => $options ?? [], 'os' => match (true) { is_a($frame['class'], BSDBuilder::class, true) => 'BSD', is_a($frame['class'], LinuxBuilder::class, true) => 'Linux', is_a($frame['class'], MacOSBuilder::class, true) => 'macOS', is_a($frame['class'], WindowsBuilder::class, true) => 'Windows', default => 'Unknown', }, 'file' => $frame['file'] ?? null, 'line' => $frame['line'] ?? null, ]; } } } }