From ee2afb08f739405da9be50b1eb2383785849c2a9 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 28 Aug 2026 20:59:23 +0800 Subject: [PATCH] Translate all Chinese notes into English --- bin/dump-ast.php | 8 +- bin/extractor.php | 2 +- src/Backend/Clang.php | 6 +- src/Backend/CompilerBackend.php | 82 +++---- src/Backend/CompilerFactory.php | 26 +- src/Backend/Gcc.php | 2 +- src/Backend/GccLikeBackend.php | 22 +- src/Backend/Msvc.php | 52 ++-- src/Build/NativeBuildConfigurationTrait.php | 57 ++--- src/Build/SourcePipelineTrait.php | 33 +-- src/CompilerBase.php | 224 +++++++++++------- src/Context/CompilationStateTrait.php | 8 +- src/Entity/FunctionDef.php | 2 +- src/Extractor.php | 78 +++--- src/Generator/CallArgumentGenerator.php | 34 ++- src/Generator/ClosureGenerator.php | 3 +- src/Generator/ResourceFileGenerator.php | 77 +++--- src/Installer/LibPhpInstaller.php | 14 +- src/Metadata/Constants.php | 8 +- src/Optimizer/FuncCallOptimizer.php | 7 +- src/Parser/ArrayExpressionTrait.php | 9 +- src/Parser/AssignOpTrait.php | 12 +- src/Parser/BinaryOpTrait.php | 4 +- src/Parser/ForeachTrait.php | 6 +- src/Parser/FunctionCallTrait.php | 4 +- src/Parser/MethodCallTrait.php | 22 +- src/Parser/PropertyAccessTrait.php | 6 +- src/Parser/SwitchTrait.php | 2 +- src/Platform/PlatformBase.php | 60 ++--- src/Platform/UnixPlatform.php | 29 +-- src/Platform/Windows.php | 32 +-- src/Preprocessor.php | 40 ++-- src/PythonTools/Converter/PythonAstLoader.php | 4 +- .../Converter/PythonToTypePhpConverter.php | 26 +- src/Resolver/MagicMethodDetector.php | 2 +- src/Resolver/NameResolutionTrait.php | 26 +- src/Resolver/PropertyAccessResolver.php | 16 +- src/Resolver/Reflection.php | 4 +- src/Symbol/SymbolRepository.php | 5 +- src/Translator.php | 211 +++++++++-------- .../NativeTypeCompatibilityTrait.php | 53 +++-- src/compiler.php | 16 +- src/gen_stub.php | 18 +- 43 files changed, 736 insertions(+), 616 deletions(-) diff --git a/bin/dump-ast.php b/bin/dump-ast.php index 34524e1b..631aa6f0 100755 --- a/bin/dump-ast.php +++ b/bin/dump-ast.php @@ -2,11 +2,11 @@ + * Usage: php bin/dump-ast.php * - * 示例: + * Examples: * php bin/dump-ast.php examples/hello.php * php bin/dump-ast.php src/compiler.php */ @@ -231,7 +231,7 @@ function dumpNode(NodeAbstract $node, int $depth = 0): void $end = $node->getEndLine(); $subInfo = ''; - // 为常见节点类型提取关键信息 + // Extract key information for common node types. switch (true) { case $node instanceof Node\Expr\Variable: $subInfo = ' $' . ($node->name === null ? '(unset)' : (is_string($node->name) ? $node->name : '...')); diff --git a/bin/extractor.php b/bin/extractor.php index b479651f..683d6139 100644 --- a/bin/extractor.php +++ b/bin/extractor.php @@ -151,7 +151,7 @@ function extractorMain(array $argv): void } } -// 运行主函数 +// Run the main function. if (php_sapi_name() === 'cli') { extractorMain($argv); } diff --git a/src/Backend/Clang.php b/src/Backend/Clang.php index cbed8823..3e3b2d8e 100644 --- a/src/Backend/Clang.php +++ b/src/Backend/Clang.php @@ -7,7 +7,7 @@ use TypePhp\Platform\Windows; use TypePhp\Platform\Macos; /** - * Clang 编译器后端实现 + * Clang compiler backend implementation. */ class Clang extends GccLikeBackend { @@ -34,7 +34,7 @@ class Clang extends GccLikeBackend } /** - * Windows 下优先使用 lld-link,找不到时回退到 link.exe + * On Windows, prefer lld-link; fall back to link.exe if it is not available. */ public static function detectWindowsLinker(): string { @@ -62,7 +62,7 @@ class Clang extends GccLikeBackend return 'link'; } - // ──── 钩子方法覆盖 ──── + // ──── Hook method overrides ──── protected function getCompilerPrefixFlags(): string { diff --git a/src/Backend/CompilerBackend.php b/src/Backend/CompilerBackend.php index d20bab57..87b751ad 100644 --- a/src/Backend/CompilerBackend.php +++ b/src/Backend/CompilerBackend.php @@ -5,18 +5,18 @@ namespace TypePhp\Backend; use TypePhp\Platform\PlatformBase; /** - * 编译器后端抽象基类 - * 定义所有编译器必须实现的接口 + * Abstract base class for compiler backends. + * Defines the interface that all compilers must implement. */ abstract class CompilerBackend { /** - * 平台实例 + * The platform instance. */ protected PlatformBase $platform; /** - * 最近创建的 Response File 路径,用于构建完成后清理 + * Path of the most recently created Response File, used for cleanup after the build completes. */ protected string $lastResponseFile = ''; @@ -26,17 +26,17 @@ abstract class CompilerBackend } /** - * 获取编译器名称 + * Get the compiler name. */ abstract public function getName(): string; /** - * 获取编译器命令 + * Get the compiler command. */ abstract public function getCompilerCommand(): string; /** - * 获取链接器命令 + * Get the linker command. */ abstract public function getLinkerCommand(): string; @@ -51,7 +51,7 @@ abstract class CompilerBackend } /** - * 构建完整的编译命令 + * Build the complete compile command. */ abstract public function buildCompileCommand( string $sourceFile, @@ -60,7 +60,7 @@ abstract class CompilerBackend ): string; /** - * 构建 C 文件的编译命令(不包含 C++ 特定选项) + * Build the compile command for C files (excludes C++-specific options). */ abstract public function buildCCompileCommand( string $sourceFile, @@ -69,9 +69,9 @@ abstract class CompilerBackend ): string; /** - * 构建原生源文件的编译命令(汇编/Objective-C 等,使用 -x 指定语言) + * Build the compile command for native source files (assembly/Objective-C, etc., using -x to specify the language). * - * @param string $language GCC/Clang 语言标识(assembler, objective-c, objective-c++ 等) + * @param string $language GCC/Clang language identifier (assembler, objective-c, objective-c++, etc.) */ abstract public function buildNativeCompileCommand( string $sourceFile, @@ -81,7 +81,7 @@ abstract class CompilerBackend ): string; /** - * 构建完整的链接命令 + * Build the complete link command. */ abstract public function buildLinkCommand( array $objectFiles, @@ -90,33 +90,35 @@ abstract class CompilerBackend ): string; /** - * 构建编译选项(不含文件路径) - * @param array $config 编译配置 - * - optimize: 优化级别 (0-3) - * - debug_info: 是否生成调试信息 - * - sanitize: sanitizer 类型 (address, undefined, etc.) - * - cpp_std: C++ 标准版本 - * - is_zts: 是否为 ZTS 模式 - * - build_mode: 构建模式 ('bin' or 'ext') - * - enable_profiler: 是否启用性能分析 - * - suppressed_warnings: 需要屏蔽的警告代码数组 - * - cxxflags: 用户自定义编译标志 - * - compiler_pdb: MSVC 编译器 PDB 输出路径 + * Build compile options (excludes file paths). + * + * @param array $config Compile configuration + * - optimize: optimization level (0-3) + * - debug_info: whether to generate debug information + * - sanitize: sanitizer type (address, undefined, etc.) + * - cpp_std: C++ standard version + * - is_zts: whether ZTS mode is enabled + * - build_mode: build mode ('bin' or 'ext') + * - enable_profiler: whether to enable profiling + * - suppressed_warnings: array of warning codes to suppress + * - cxxflags: user-defined compile flags + * - compiler_pdb: MSVC compiler PDB output path */ abstract public function buildCompileOptions(array $config = []): string; /** - * 构建链接选项(不含文件路径) - * @param array $config 链接配置 - * - debug_info: 是否生成调试信息 - * - no_console: 是否隐藏控制台窗口 - * - build_mode: 构建模式 ('bin' or 'ext') - * - sanitize: sanitizer 类型 + * Build link options (excludes file paths). + * + * @param array $config Link configuration + * - debug_info: whether to generate debug information + * - no_console: whether to hide the console window + * - build_mode: build mode ('bin' or 'ext') + * - sanitize: sanitizer type */ abstract public function buildLinkOptions(array $config = []): string; /** - * 获取平台实例 + * Get the platform instance. */ public function getPlatform(): PlatformBase { @@ -124,7 +126,7 @@ abstract class CompilerBackend } /** - * 格式化包含路径 + * Format include paths. */ protected function formatIncludePaths(array $includePaths): string { @@ -132,7 +134,7 @@ abstract class CompilerBackend } /** - * 格式化库路径 + * Format library paths. */ protected function formatLibraryPaths(array $libraryPaths): string { @@ -140,7 +142,7 @@ abstract class CompilerBackend } /** - * 格式化库文件 + * Format library files. */ protected function formatLibraries(array $libraries): string { @@ -157,11 +159,11 @@ abstract class CompilerBackend } /** - * 将目标文件列表写入 Response File,避免命令行参数过长超出 OS 限制(Windows 8191 字符) + * Write the object file list to a Response File to avoid exceeding the OS command-line length limit (8191 characters on Windows). * - * @param array $objectFiles 目标文件路径列表 - * @param string $targetFile 最终输出文件路径(Response File 写入同目录) - * @return string 链接器参数,如 @build/project.rsp + * @param array $objectFiles List of object file paths. + * @param string $targetFile Final output file path (the Response File is written to the same directory). + * @return string Linker argument, e.g. @build/project.rsp */ protected function createResponseFile(array $objectFiles, string $targetFile): string { @@ -169,7 +171,7 @@ abstract class CompilerBackend $this->lastResponseFile = $rspFile; $lines = []; foreach ($objectFiles as $file) { - // 路径含空格时用双引号包裹,MSVC link.exe 和 GCC/Clang 均支持 + // Wrap paths containing spaces in double quotes; supported by both MSVC link.exe and GCC/Clang. if (str_contains($file, ' ')) { $file = '"' . $file . '"'; } @@ -180,7 +182,7 @@ abstract class CompilerBackend } /** - * 删除最近创建的 Response File 临时文件 + * Delete the most recently created Response File temporary file. */ public function cleanupResponseFile(): void { diff --git a/src/Backend/CompilerFactory.php b/src/Backend/CompilerFactory.php index 8fa86728..c2eee671 100644 --- a/src/Backend/CompilerFactory.php +++ b/src/Backend/CompilerFactory.php @@ -8,24 +8,24 @@ use TypePhp\Platform\Linux; use TypePhp\Platform\Macos; /** - * 编译器工厂类 - * 根据平台自动创建合适的编译器后端 + * Compiler factory. + * Automatically creates the appropriate compiler backend based on the platform. */ class CompilerFactory { /** - * 创建默认编译器后端 + * Create the default compiler backend. */ public static function create(PlatformBase $platform): CompilerBackend { if ($platform instanceof Windows) { - // Windows 默认使用 MSVC + // Windows uses MSVC by default. return new Msvc($platform, $platform->getDefaultCompiler()); } elseif ($platform instanceof Linux) { - // Linux 默认使用 GCC + // Linux uses GCC by default. return new Gcc($platform, $platform->getDefaultCompiler()); } elseif ($platform instanceof Macos) { - // macOS 默认使用 Clang + // macOS uses Clang by default. return new Clang($platform, $platform->getDefaultCompiler()); } else { throw new \RuntimeException("Unsupported platform: " . $platform->getName()); @@ -33,7 +33,7 @@ class CompilerFactory } /** - * 根据配置、环境变量和平台默认值解析编译器命令 + * Resolve the compiler command based on configuration, environment variables, and platform defaults. */ public static function detectCompilerName(PlatformBase $platform, string $configuredCompiler = ''): string { @@ -57,7 +57,7 @@ class CompilerFactory } /** - * 创建指定类型的编译器后端 + * Create a compiler backend of the specified type. */ public static function createByName(string $compilerName, PlatformBase $platform): CompilerBackend { @@ -93,17 +93,17 @@ class CompilerFactory } /** - * 自动检测并创建编译器和平台 + * Auto-detect and create the compiler and platform. */ public static function autoDetect(string $compilerName = '', ?PlatformBase $platform = null): array { - // 创建平台 + // Create the platform. $platform ??= \TypePhp\Platform\PlatformFactory::create(); - - // 创建编译器 + + // Create the compiler. $compilerName = self::detectCompilerName($platform, $compilerName); $compiler = self::createByName($compilerName, $platform); - + return [ 'platform' => $platform, 'compiler' => $compiler, diff --git a/src/Backend/Gcc.php b/src/Backend/Gcc.php index 1209b4d3..91fcb5cc 100644 --- a/src/Backend/Gcc.php +++ b/src/Backend/Gcc.php @@ -5,7 +5,7 @@ namespace TypePhp\Backend; use TypePhp\Platform\PlatformBase; /** - * GCC 编译器后端实现 + * GCC compiler backend implementation. */ class Gcc extends GccLikeBackend { diff --git a/src/Backend/GccLikeBackend.php b/src/Backend/GccLikeBackend.php index 8179ade5..b83e8274 100644 --- a/src/Backend/GccLikeBackend.php +++ b/src/Backend/GccLikeBackend.php @@ -6,9 +6,9 @@ use TypePhp\Platform\PlatformBase; use TypePhp\Platform\Windows; /** - * GCC/Clang 共享后端基类 - * 包含 Unix-like 编译器(GCC、Clang)的通用命令行构建逻辑。 - * 子类只需覆盖平台差异的钩子方法。 + * Shared backend base class for GCC/Clang. + * Contains the common command-line construction logic for Unix-like compilers (GCC, Clang). + * Subclasses only need to override the platform-specific hook methods. */ abstract class GccLikeBackend extends CompilerBackend { @@ -37,21 +37,21 @@ abstract class GccLikeBackend extends CompilerBackend return $headerFile . '.gch'; } - // ──── 钩子方法(子类覆盖点) ──── + // ──── Hook methods (subclass override points) ──── - /** 编译器特定的前缀标志(如 MSVC 兼容模式) */ + /** Compiler-specific prefix flags (e.g. MSVC compatibility mode). */ protected function getCompilerPrefixFlags(): string { return ''; } - /** 链接器输出标志(-o vs /OUT:) */ + /** Linker output flag (-o vs /OUT:). */ protected function getLinkerOutputFlag(): string { return '-o'; } - /** 格式化 sanitizer 标志 */ + /** Format the sanitizer flag. */ protected function formatSanitizerFlag(string $sanitizer): string { return match ($sanitizer) { @@ -61,7 +61,7 @@ abstract class GccLikeBackend extends CompilerBackend }; } - /** 获取 PIC 标志 */ + /** Get the PIC flag. */ protected function getPICFlag(array $config): string { if ((!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) || !empty($config['pic'])) { @@ -70,7 +70,7 @@ abstract class GccLikeBackend extends CompilerBackend return ''; } - /** 构建 GCC/Clang 共享编译选项,C 和 C++ 编译路径都复用这里 */ + /** Build the shared GCC/Clang compile flags; reused by both the C and C++ compilation paths. */ protected function buildSharedCompileFlags(array $config, bool $includeCppStd = false): string { $cmd = ''; @@ -146,7 +146,7 @@ abstract class GccLikeBackend extends CompilerBackend return ' -include ' . escapeshellarg($precompiledHeader['header']); } - /** 获取平台特定的链接选项 */ + /** Get platform-specific link options. */ protected function getPlatformLinkFlags(array $config): string { $flags = ''; @@ -181,7 +181,7 @@ abstract class GccLikeBackend extends CompilerBackend return $flags; } - // ──── 抽象方法实现 ──── + // ──── Abstract method implementations ──── public function buildCompileCommand(string $sourceFile, string $outputFile, array $options = []): string { diff --git a/src/Backend/Msvc.php b/src/Backend/Msvc.php index 64883133..3e70af5d 100644 --- a/src/Backend/Msvc.php +++ b/src/Backend/Msvc.php @@ -5,7 +5,7 @@ namespace TypePhp\Backend; use TypePhp\Platform\Windows; /** - * MSVC 编译器后端实现 + * MSVC compiler backend implementation. */ class Msvc extends CompilerBackend { @@ -131,7 +131,7 @@ class Msvc extends CompilerBackend } /** - * 构建 C 文件的编译命令(不包含 C++ 特定选项) + * Build the compile command for C files (excludes C++-specific options). */ public function buildCCompileCommand(string $sourceFile, string $outputFile, array $options = []): string { @@ -145,20 +145,20 @@ class Msvc extends CompilerBackend $cmd .= ' ' . $this->formatIncludePaths($options['include_paths']); } - // 平台宏定义 + // Platform macro definitions. $cmd .= $this->buildCommonCompileFlags($options, false); - // 注意:C 文件不使用 /EHsc, /std:c++17, /MD 等 C++ 特定选项 + // Note: C files do not use C++-specific options such as /EHsc, /std:c++17, /MD. return $cmd; } /** - * 构建原生源文件的编译命令 + * Build the compile command for native source files. * - * MSVC 仅支持 C 文件(/TC),汇编和 ObjC 文件不受支持 + * MSVC only supports C files (/TC); assembly and ObjC files are not supported. * - * @param string $language 语言标识 + * @param string $language Language identifier. */ public function buildNativeCompileCommand(string $sourceFile, string $outputFile, array $options = [], string $language = ''): string { @@ -214,42 +214,42 @@ class Msvc extends CompilerBackend } /** - * 构建编译选项(实现抽象方法) + * Build compile options (implements the abstract method). */ public function buildCompileOptions(array $config = []): string { return $this->buildCommonCompileFlags($config, true); } - + /** - * 构建链接选项(实现抽象方法) + * Build link options (implements the abstract method). */ public function buildLinkOptions(array $config = []): string { $cmd = ''; - - // 调试 + + // Debug. if (!empty($config['debug'])) { $cmd .= ' /DEBUG'; } - // Windows 子系统 + // Windows subsystem. if (!empty($config['no_console'])) { $cmd .= ' ' . $this->platform->getSubsystemOptions(true); } - // CRT 配置 + // CRT configuration. $cmd .= ' ' . $this->platform->getCrtConfig(); - // 扩展模块选项 + // Extension module options. if (!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) { $cmd .= ' /DLL'; } - // nologo + // nologo. $cmd .= ' /nologo'; - // LTO(链接时代码生成) + // LTO (Link Time Code Generation). if (!empty($config['lto'])) { $cmd .= ' /LTCG'; } @@ -258,20 +258,20 @@ class Msvc extends CompilerBackend } /** - * 编译 Windows 资源文件 (.rc) 为目标文件 (.res) + * Compile a Windows resource file (.rc) into an object file (.res). * - * 使用 rc.exe(MSVC 资源编译器)将 .rc 文件编译为 .res 文件 - * .res 文件可以直接传给 link.exe 作为输入 + * Uses rc.exe (the MSVC resource compiler) to compile a .rc file into a .res file. + * The .res file can be passed directly to link.exe as input. * - * @param string $rcFile 资源文件路径 (.rc) - * @param string $resFile 输出资源文件路径 (.res) - * @return string 编译命令 + * @param string $rcFile Resource file path (.rc). + * @param string $resFile Output resource file path (.res). + * @return string The compile command. */ public function compileResourceFile(string $rcFile, string $resFile): string { - // rc.exe 是 MSVC 自带的资源编译器 - // /nologo: 不显示版权信息 - // /fo: 指定输出文件 + // rc.exe is the resource compiler bundled with MSVC. + // /nologo: suppress the copyright banner. + // /fo: specify the output file. $cmd = 'rc.exe /nologo'; $cmd .= ' /fo ' . escapeshellarg($resFile); $cmd .= ' ' . escapeshellarg($rcFile); diff --git a/src/Build/NativeBuildConfigurationTrait.php b/src/Build/NativeBuildConfigurationTrait.php index bc9dd32b..dc28d40c 100644 --- a/src/Build/NativeBuildConfigurationTrait.php +++ b/src/Build/NativeBuildConfigurationTrait.php @@ -20,7 +20,7 @@ trait NativeBuildConfigurationTrait $this->getPhpxDir() . '/src/misc', ]; - // 根据平台添加 PHP 包含路径 + // Add the platform-specific PHP include paths if ($platform instanceof Windows) { $phpSdkPaths = $platform->buildPhpSdkIncludePaths($this->getPhpDir()); $includePaths = array_merge($includePaths, $phpSdkPaths); @@ -28,7 +28,7 @@ trait NativeBuildConfigurationTrait // Linux/macOS $phpPaths = $platform->buildPhpIncludePaths($this->getPhpDir()); $includePaths = array_merge($includePaths, $phpPaths); - // 内置 mpdecimal 头文件目录 + // Bundled mpdecimal header directories $includePaths[] = $this->getPhpxDir() . '/thirdparty/mpdecimal/libmpdec'; $includePaths[] = $this->getPhpxDir() . '/thirdparty/mpdecimal/libmpdec++'; } @@ -43,7 +43,7 @@ trait NativeBuildConfigurationTrait $this->getPhpxDir() . '/lib', ]; - // 根据平台添加 PHP 库路径 + // Add the platform-specific PHP library paths if ($platform instanceof Windows) { $phpLibPaths = $platform->buildPhpSdkLibPaths($this->getPhpDir()); $libraryPaths = array_merge($libraryPaths, $phpLibPaths); @@ -57,45 +57,45 @@ trait NativeBuildConfigurationTrait } /** - * 获取库文件 + * Get the library files to link against */ protected function getLibraries(): array { $platform = $this->getPlatform(); $libraries = []; - // phpx 库(根据平台使用不同的文件名格式) + // phpx library (file name format differs by platform) $phpxLibPath = $this->findPhpxLibrary(); if ($phpxLibPath === null) { $this->error($this->getPhpxLibraryErrorMessage()); } $libraries[] = $phpxLibPath; - // extension 和 bin 模式都需要链接 PHP 库 + // Both extension and bin modes need to link the PHP library if ($platform instanceof Windows) { - // Windows: 根据构建模式选择不同的库 + // Windows: pick different libraries based on the build mode if ($this->isBuildModeEmbed()) { - // bin 模式:需要同时链接 php8ts.lib 和 php8embed.lib - // 注意:php8ts.lib 必须在 php8embed.lib 之前,因为 embed 依赖 core - // php8ts.lib 提供 PHP 核心全局符号(executor_globals, compiler_globals, sapi_globals) + // bin mode: link both php8ts.lib and php8embed.lib + // Note: php8ts.lib must come before php8embed.lib because embed depends on core + // php8ts.lib provides the PHP core global symbols (executor_globals, compiler_globals, sapi_globals) if (!empty($this->windowsPhpCoreLib)) { - $libraries[] = $this->windowsPhpCoreLib; // 不添加引号 + $libraries[] = $this->windowsPhpCoreLib; // do not quote } - // php8embed.lib 提供嵌入 API + // php8embed.lib provides the embed API if (!empty($this->windowsPhpEmbedLib)) { - $libraries[] = $this->windowsPhpEmbedLib; // 不添加引号 + $libraries[] = $this->windowsPhpEmbedLib; // do not quote } } else { - // ext 模式:只使用 php8ts.lib 或 php8.lib(PHP 扩展) + // ext mode: use only php8ts.lib or php8.lib (PHP extension) if (!empty($this->windowsPhpCoreLib)) { - $libraries[] = $this->windowsPhpCoreLib; // 不添加引号 + $libraries[] = $this->windowsPhpCoreLib; // do not quote } } - // 添加 Windows API 库(Win32 GUI 程序需要) - $libraries[] = 'user32.lib'; // Windows UI 函数(CreateWindow, MessageBox 等) - $libraries[] = 'gdi32.lib'; // GDI 图形函数 - $libraries[] = 'kernel32.lib'; // 核心 Windows API + // Add the Windows API libraries (required by Win32 GUI programs) + $libraries[] = 'user32.lib'; // Windows UI functions (CreateWindow, MessageBox, etc.) + $libraries[] = 'gdi32.lib'; // GDI graphics functions + $libraries[] = 'kernel32.lib'; // Core Windows API $libraries[] = 'gmp.lib'; $libraries[] = 'gmpxx.lib'; $libraries[] = 'mpfr.lib'; @@ -117,10 +117,12 @@ trait NativeBuildConfigurationTrait } /** - * 解析 phpx 库文件路径,库不存在时返回 null。 + * Resolve the phpx library file path, returning null when the library does + * not exist. * - * Windows 使用 phpx.lib(无 lib 前缀);其他平台优先使用共享库 - * (libphpx.so / libphpx.dylib),找不到时回退到静态库 libphpx.a。 + * Windows uses phpx.lib (no lib prefix); other platforms prefer the shared + * library (libphpx.so / libphpx.dylib) and fall back to the static library + * libphpx.a when it is not found. */ protected function findPhpxLibrary(): ?string { @@ -131,8 +133,8 @@ trait NativeBuildConfigurationTrait return is_file($phpxLibPath) ? $phpxLibPath : null; } - // Linux/macOS:共享库优先,静态库兜底 - // getSharedLibraryExtension() 返回的值可能带点或不带点,需要统一处理 + // Linux/macOS: prefer the shared library, fall back to the static library + // getSharedLibraryExtension() may or may not include a leading dot, so normalize it $sharedLibExt = ltrim($platform->getSharedLibraryExtension(), '.'); $phpxLibPath = $this->getPhpxDir() . '/lib/libphpx.' . $sharedLibExt; if (is_file($phpxLibPath)) { @@ -152,7 +154,7 @@ trait NativeBuildConfigurationTrait } /** - * 生成 phpx 库缺失时的错误信息 + * Generate the error message shown when the phpx library is missing */ protected function getPhpxLibraryErrorMessage(): string { @@ -175,8 +177,9 @@ trait NativeBuildConfigurationTrait } /** - * 前置检测 phpx 库是否可用,在编译开始前报错, - * 避免所有源文件编译完成后才在链接阶段失败。 + * Verify the phpx library is available up front and fail before compilation + * starts, rather than only failing at link time after all source files have + * been compiled. */ protected function validatePhpxLibrary(): void { diff --git a/src/Build/SourcePipelineTrait.php b/src/Build/SourcePipelineTrait.php index 4fbf35e8..4514e8a8 100644 --- a/src/Build/SourcePipelineTrait.php +++ b/src/Build/SourcePipelineTrait.php @@ -34,7 +34,7 @@ trait SourcePipelineTrait $path = $realpath; if (is_dir($path)) { - // 目录模式:不解析 YAML + // Directory mode: no YAML parsing $list = $this->getFilesFromDir($path); $targetName = basename($path); $this->setTargetName($targetName); @@ -42,10 +42,10 @@ trait SourcePipelineTrait } else { $ext = pathinfo($path, PATHINFO_EXTENSION); if ($ext === 'yml' || $ext === 'yaml') { - // YAML 配置模式:先解析 YAML + // YAML config mode: parse the YAML first $list = $this->parseProjectYaml($path); } elseif ($ext === 'php') { - // 单文件模式:不解析 YAML + // Single-file mode: no YAML parsing $list = [$path]; $targetName = FileScanner::getFileName($path); $this->setTargetName($targetName); @@ -55,7 +55,8 @@ trait SourcePipelineTrait } } - // 在所有配置加载完成后,应用命令行参数(确保优先级最高) + // Apply command-line arguments after all configuration is loaded (so they + // take the highest precedence) $this->applyCommandLineArguments(); // The generated public import stub is an output artifact, not an input @@ -100,19 +101,22 @@ trait SourcePipelineTrait } } - // 仅在 PHP 脚本入口(bin/tpc.php)前置检测 phpx 库:缺少库立即 fatal, - // 避免继续向下执行到文件处理/编译阶段才报错。已编译的 tpc 可执行文件 - // 在进入 main() 前就由动态链接器加载 libphpx,无需(也无法)在此检测。 + // Pre-check the phpx library only at the PHP script entry (bin/tpc.php): + // a missing library fails immediately rather than surfacing later during + // file processing/compilation. The compiled tpc executable has libphpx + // loaded by the dynamic linker before entering main(), so checking here + // is neither needed nor possible. if (defined('TYPEPHP_PHP_SCRIPT_ENTRY') && !($this->getPlatform() instanceof Wasi)) { $this->validatePhpxLibrary(); } $this->validateCompilerToolchain(); - // shell_exec 和 define 已通过 php::fn:: 直接调用,无需动态符号表 + // shell_exec and define are already called directly via php::fn::, so no + // dynamic symbol table is needed - // Windows 的所有构建模式都依赖 PHPX 导入库和运行库。 - // 其他平台仅在嵌入式构建模式下执行现有检查。 + // All Windows build modes depend on the PHPX import library and runtime. + // Other platforms only run the existing checks in embedded build mode. if ($this->isBuildModeEmbed() || $this->getPlatform() instanceof Windows) { foreach ($this->getPlatform()->getBuildLibraryWarnings( $this->getPhpDir(), @@ -136,7 +140,7 @@ trait SourcePipelineTrait $files = $this->filterIgnoredFiles($files); $this->discoverNativeClassDeclarations($files); - // 分析 PHP 文件,预处理 + // Analyze and preprocess the PHP files foreach ($files as $k => $file) { if (FileScanner::isPhpFile($file)) { try { @@ -258,7 +262,7 @@ trait SourcePipelineTrait $sourceFiles = []; $validSourceCount = 0; - // 生成 C++ 文件 + // Generate the C++ files foreach ($files as $k => $file) { try { if (FileScanner::isPhpFile($file)) { @@ -293,10 +297,11 @@ trait SourcePipelineTrait $this->genLibraryImportStub($files); } - // 生成构建期内部头文件:函数声明、运行时数据声明 + // Generate the build-time internal headers: function declarations and + // runtime data declarations $this->genFunctionDeclarations($this->getIncludeDir() . "/php_{$this->targetName}_func_decl.h"); $this->genDataDeclarations($this->getIncludeDir() . "/php_{$this->targetName}_data_decl.h"); - // 生成扩展模块源文件 + // Generate the extension module source file $sourceFiles[] = $this->genExtension(); return $sourceFiles; diff --git a/src/CompilerBase.php b/src/CompilerBase.php index dce4d484..c5327c65 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -288,12 +288,14 @@ class CompilerBase implements PropertyAccessContext protected int $classIndex = 0; /** - * 用户定义(请求生命周期)类名 → ID,运行期为 THREAD_LOCAL 缓存,RSHUTDOWN 清理 + * User-defined (request-lifetime) class name → ID. Backed by a THREAD_LOCAL + * cache at runtime and cleared on RSHUTDOWN. * @var array */ protected array $classMap = []; /** - * 内置/编译产物(模块生命周期)类名 → ID,PHP 启动完成后惰性填充,RSHUTDOWN 不清理 + * Built-in / compiled-output (module-lifetime) class name → ID. Lazily + * populated after PHP startup and NOT cleared on RSHUTDOWN. * @var array */ protected array $persistentClassMap = []; @@ -305,21 +307,26 @@ class CompilerBase implements PropertyAccessContext protected int $funcIndex = 0; /** - * 用户定义(请求生命周期)函数/方法 → ID,运行期为 THREAD_LOCAL 缓存,RSHUTDOWN 清理 - * key 为函数名或 `Class::method` + * User-defined (request-lifetime) function/method → ID. Backed by a + * THREAD_LOCAL cache at runtime and cleared on RSHUTDOWN. + * Key is a function name or `Class::method`. * @var array */ protected array $funcMap = []; /** - * 内置/编译产物(模块生命周期)函数/方法 → ID,PHP 启动完成后惰性填充,RSHUTDOWN 不清理 - * key 为函数名或 `Class::method` + * Built-in / compiled-output (module-lifetime) function/method → ID. Lazily + * populated after PHP startup and NOT cleared on RSHUTDOWN. + * Key is a function name or `Class::method`. * @var array */ protected array $persistentFuncMap = []; protected int $persistentFuncIndex = 0; /** - * 内置/编译产物类的声明属性 offset 缓存,key 为 `Class::prop`,惰性填充,RSHUTDOWN 不清理。 - * 属性解析仅覆盖编译类与内置类的声明属性(进程级稳定),用户类属性走字符串路径,不进缓存。 + * Declared-property offset cache for built-in / compiled-output classes. + * Key is `Class::prop`; lazily populated and NOT cleared on RSHUTDOWN. + * Property resolution only covers declared properties of compiled classes + * and built-in classes (process-stable). User-class properties go through + * the string path and never enter this cache. */ protected array $persistentPropMap = []; protected int $persistentPropIndex = 0; @@ -345,10 +352,11 @@ class CompilerBase implements PropertyAccessContext 'mixed' => Type::VAR, 'null' => Type::VAR, 'any' => Type::VAR, - // callable 类型,可以是字符串、数组、对象 - // 1) 'foo' 函数名称字符串, 2) [ $obj, 'bar' ] 对象方法数组, 3) Closure 对象, 4) [ 'class', 'staticMethod'] 类名+静态方法数组 + // The callable type can be a string, array, or object: + // 1) 'foo' function-name string, 2) [ $obj, 'bar' ] object-method array, + // 3) a Closure object, 4) [ 'class', 'staticMethod' ] class + static-method array. 'callable' => Type::VAR, - // iterable 类型,可以是数组或者对象 + // The iterable type can be an array or an object. 'iterable' => Type::VAR, 'stream' => Type::STREAM, 'bigint' => Type::BIGINT, @@ -361,13 +369,15 @@ class CompilerBase implements PropertyAccessContext protected array $internalConstants = []; /** - * 存储所有函数、类方法的声明,key 是 符号名称,Value 是函数、类方法所在的文件名称 + * Stores the declaration of every function and class method. Key is the + * symbol name; value is the file in which the function or method is declared. * @var array */ protected array $symbolDeclInFile = []; /** - * 存储所有函数、类方法的调用,key 是 文件名称,Value 是函数、类方法调用的列表数组 + * Stores every function / class-method call. Key is the file name; value is + * a list of the functions / class methods called within that file. * @var array> */ protected array $symbolCallInFile = []; @@ -400,7 +410,7 @@ class CompilerBase implements PropertyAccessContext protected string $dir; /** - * 原始值,可能包含 `\\` 多层空间. + * The raw namespace value, which may contain `\\` multi-level separators. */ protected string $namespace = ''; protected string $method = ''; @@ -413,7 +423,7 @@ class CompilerBase implements PropertyAccessContext protected array $useImportAliases = []; /** - * 原始类名,不包含命名空间. + * The raw class name, without the namespace. */ protected string $class = ''; protected string $parentClass = ''; @@ -469,7 +479,7 @@ class CompilerBase implements PropertyAccessContext protected bool $bigintTypes = false; protected string $rootPath; protected string $buildDir; - protected string $outputDir = ''; // -o 参数指定的输出目录 + protected string $outputDir = ''; // Output directory specified by the -o option protected int $debugLine = 0; protected CLImate $climate; protected bool $stubFile = false; @@ -483,26 +493,28 @@ class CompilerBase implements PropertyAccessContext protected Parser $parser; protected string $phpVersion = self::DEFAULT_PHP_VERSION; protected PrettyPrinter $printer; - protected bool $isPhpZts = false; // PHP 是否为线程安全版本 + protected bool $isPhpZts = false; // Whether the PHP build is thread-safe (ZTS) - // Windows 平台:保存检测到的 PHP lib 文件路径 - protected string $windowsPhpEmbedLib = ''; // php8embed.lib 路径 - protected string $windowsPhpCoreLib = ''; // php8ts.lib 或 php8.lib 路径 + // Windows platform: store the detected PHP lib file paths. + protected string $windowsPhpEmbedLib = ''; // Path to php8embed.lib + protected string $windowsPhpCoreLib = ''; // Path to php8ts.lib or php8.lib - // 新的平台和编译器抽象层(可选使用) + // New platform and compiler abstraction layers (optional to use). protected ?PlatformBase $platform = null; protected ?CompilerBackend $compilerBackend = null; /** - * 在预处理阶段获取所有类的方法名称,检测子类和父类中存在的同名方法,解决动态绑定方法调用的问题 - * `static::methodCall()` - * `$this->methodCall()` 子类和父类中存在同名方法 + * Records all class method names collected during the preprocessing phase. + * Used to detect methods with the same name declared in both a child class + * and its parent class, resolving dynamic method-binding calls such as + * `static::methodCall()` and `$this->methodCall()` where a parent and a + * child class both define the method. * @var array */ protected array $classMethodOverride = []; /** - * 存储所有类继承关系,类名必须全部为小写 + * Stores all class inheritance relationships. Class names must be all lowercase. * @var array */ protected SymbolRepository $symbols; @@ -1183,8 +1195,10 @@ class CompilerBase implements PropertyAccessContext } /** - * 判断类的符号指针是否在 PHP 模块生命周期内稳定(MINIT 注册,跨请求缓存安全)。 - * 编译产物(本单元编译的类/接口)与 PHP 内置类/接口均满足条件。 + * Determine whether a class's symbol pointer is stable across the PHP + * module lifetime (registered at MINIT, safe to cache across requests). + * Compiled output (classes/interfaces compiled in this unit) and PHP + * built-in classes/interfaces both satisfy this condition. */ protected function isProcessStableClass(string $className): bool { @@ -1196,8 +1210,9 @@ class CompilerBase implements PropertyAccessContext } /** - * 判断函数/方法符号指针是否在 PHP 模块生命周期内稳定。 - * `Class::method` 形式的 key 以其所属类的稳定性为准。 + * Determine whether a function/method symbol pointer is stable across the + * PHP module lifetime. For a `Class::method` key, stability is determined + * by the class it belongs to. */ protected function isProcessStableFunction(string $funcName): bool { @@ -1251,13 +1266,15 @@ class CompilerBase implements PropertyAccessContext } /** - * @param string $className 必须是带有命名空间的完整类名 + * @param string $className Must be a fully-qualified class name (with namespace). * - * 注意:不存在与用户定义类对应的动态 propMap(区别于 classMap/funcMap)。 - * 属性 offset 缓存的前提是编译期能解析出声明属性(PropertyAccessResolver - * 只接受编译类的 ClassDef 或内置类的反射声明属性),用户类在编译期不可见, - * 其属性访问一律走 `.attr(name)` 字符串路径,因此所有条目必然进程级稳定, - * 全部进入 persistentPropMap。 + * Note: there is no dynamic propMap for user-defined classes (unlike + * classMap/funcMap). The property-offset cache assumes declared properties + * can be resolved at compile time (PropertyAccessResolver only accepts a + * compiled ClassDef or the reflected declared properties of a built-in + * class). User classes are not visible at compile time, so their property + * accesses always go through the `.attr(name)` string path. As a result, + * every entry is necessarily process-stable and goes into persistentPropMap. */ protected function getPropertyId(string $className, string $propName): int { @@ -1555,10 +1572,12 @@ class CompilerBase implements PropertyAccessContext } return $this->withoutLocalClassEntryHoisting(function () use ($default): string { /* - * 函数参数默认值只能为字面量,无法使用表达式获取值。 - * 但 PHP 自 5.6 起支持在默认参数值中使用常量表达式,包括 - * 类常量(self::FOO、ClassName::BAR、\Full\Class::BAZ), - * 编译器需要在编译期将其折叠为对应的字面量。 + * Function parameter default values may only be literals; they + * cannot be obtained through an expression. Since PHP 5.6, however, + * constant expressions are allowed in default parameter values, + * including class constants (self::FOO, ClassName::BAR, + * \Full\Class::BAZ). The compiler must fold these into the + * corresponding literal at compile time. * * PHP 8.1 also permits `new` in selected default-value contexts. * These expressions are emitted into standalone helper functions, @@ -1585,8 +1604,9 @@ class CompilerBase implements PropertyAccessContext } /** - * 在 for/foreach 等包含子语句的语句,之前检查当前待添加的代码是否为空, - * 如果不为空,需要将语句追加到 {} 作用域符号之前. + * For statements containing sub-statements (for/foreach, etc.), check + * whether the currently pending code is empty. If not, the pending + * statements must be emitted before the opening `{` scope brace. */ protected function parseBeforeStmtLines(): string { @@ -1914,7 +1934,7 @@ class CompilerBase implements PropertyAccessContext } /** - * 尽可能转为数字,优先级 浮点 > 整数 > 字符串. + * Convert to a number whenever possible, with priority float > integer > string. */ protected function parseNumericIdentifier(NodeAbstract $expr): string { @@ -2002,7 +2022,7 @@ class CompilerBase implements PropertyAccessContext if ($this->classDef?->nativeObject) { $this->fatalError($expr, 'Native classes do not support `new static()`'); } - // 无法在编译期获得 static 类的准确类名 + // The exact class name of a `static` class cannot be obtained at compile time. return ''; } else { return $this->getNamespacedClassName($class); @@ -2104,10 +2124,10 @@ class CompilerBase implements PropertyAccessContext protected function detectDeclaredClassOfExpr(NodeAbstract $expr): string { - // 对象表达式有两类类型信息: - // 1. detectClassOfExpr() 返回“实际可推断的类”,例如 new Foo()、typed object 变量; - // 2. getDeclaredObjectType() 返回变量声明/首次赋值记录的 declared type,可能是接口或抽象类。 - // 参数和属性赋值检查需要先使用实际类;实际类不可知时才退回 declared type。 + // Object expressions carry two kinds of type information: + // 1. detectClassOfExpr() returns the "actually inferable class", e.g. new Foo() or a typed object variable; + // 2. getDeclaredObjectType() returns the declared type recorded at declaration/first assignment, which may be an interface or abstract class. + // Parameter and property-assignment checks prefer the actual class, falling back to the declared type only when the actual class is unknown. $class = $this->detectClassOfExpr($expr); if ($class !== '') { return $class; @@ -2120,13 +2140,22 @@ class CompilerBase implements PropertyAccessContext protected function isObjectClassStaticallyAssignableTo(string $class, string $expected): bool { - // 这个函数只回答“编译器在静态阶段能否证明 $class is-a $expected”。 - // 这里禁止使用 class_exists()/interface_exists()/is_a() 去查询当前运行编译器的 PHP 进程: - // - 编译器进程已加载的 Composer/工具类,不等价于被编译项目运行时可用的类; - // - 自举编译时还会把编译器自身依赖的外部库误判为项目静态类; - // - AOT 的静态判断必须只依赖 hasClass()/hasInterface() 记录的项目类图,或明确的内置类/接口。 - // 如果类不属于这些集合,说明它是动态类/外部库类,不能在这里静态判定,应返回 false, - // 由调用处决定是延迟到运行时 php::toObject()/TypeCheck,还是因为确定 concrete mismatch 而 fatal。 + // This function only answers "can the compiler prove at the static + // stage that $class is-a $expected". It must not use + // class_exists()/interface_exists()/is_a() to query the PHP process + // currently running the compiler: + // - Composer/tool classes already loaded in the compiler process are not + // equivalent to classes available at runtime for the compiled project; + // - during bootstrapping, the compiler's own external dependencies would + // be mistaken for the project's static classes; + // - AOT static analysis must rely only on the project class graph + // recorded by hasClass()/hasInterface(), or on explicitly built-in + // classes/interfaces. + // If a class is not in one of these sets, it is a dynamic / external + // library class and cannot be statically determined here. Return false + // and let the caller decide whether to defer to runtime + // php::toObject()/TypeCheck, or to fail fatally because of a + // determined concrete mismatch. $class = ltrim($class, '\\'); $expected = ltrim($expected, '\\'); if (strcasecmp($class, $expected) === 0) { @@ -2146,10 +2175,13 @@ class CompilerBase implements PropertyAccessContext protected function isKnownConcreteObjectExpr(NodeAbstract $expr, string $class): bool { - // “已知 concrete object” 的要求比“表达式写着 new SomeClass”更严格: - // 只有 AOT 项目类图中的类或内置类,编译器才能在静态阶段确认其继承关系。 - // 外部库类即使出现在 new 表达式中,也不能用当前编译器进程的反射信息判定, - // 否则会把编译器/Composer 运行环境泄漏进被编译项目的类型系统。 + // "Known concrete object" is stricter than "the expression literally + // says new SomeClass": only classes in the AOT project class graph or + // built-in classes allow the compiler to confirm inheritance at the + // static stage. Even if an external library class appears in a new + // expression, it cannot be determined using the reflection info of the + // current compiler process; doing so would leak the compiler/Composer + // runtime environment into the type system of the compiled project. if ($class === '' || $this->isInterface($class) || $this->isAbstractClass($class)) { return false; } @@ -2390,7 +2422,7 @@ class CompilerBase implements PropertyAccessContext $lines[] = 'return ' . $tuple . ';'; return implode(PHP_EOL . $this->getIndent(), $lines); } - // 实际函数的返回值 + // The return value of the actual function. $type = $this->detectTypeOfExpr($v->expr); // In ordinary PHP mode, int +/−/* int is only conditionally an int: // runtime overflow promotes the result to float. Keep the Variant @@ -2488,7 +2520,7 @@ class CompilerBase implements PropertyAccessContext $expr = $this->parseExprAsValue($v->expr); $returnType = $this->getReturnType(); - // 匿名函数的返回值一定是 var + // The return value of an anonymous function is always var. if (!$this->context->inClosure) { if ($returnType === Type::VOID) { $this->fatalError($v, 'The return type is void, cannot return any value'); @@ -2511,7 +2543,7 @@ class CompilerBase implements PropertyAccessContext } $returnObjectCheckClass = ''; - // 返回值的表达式是一个类的对象 + // The return-value expression is an instance of a class. $objectClass = $this->detectDeclaredClassOfExpr($v->expr); $returnClass = $this->context->inClosure ? '' : $this->getReturnClass(); if ($returnClass) { @@ -2537,13 +2569,17 @@ class CompilerBase implements PropertyAccessContext [$code, $tmpVar] = $this->genUnionCheckedReturnAssignment($exprCode); $this->context->afterStmtLines[] = $this->getIndent() . 'return ' . $tmpVar . ';'; } elseif (!$this->isVarExpr($v->expr) and !$this->isScalar($v->expr)) { - // return 如果使用了 Indirect 语句,可能会导致变量提前析构,出现悬空指针 - // 将 Indirect 赋值给临时变量后,使用 Ctor::Copy 解除了 Indirect,保证内存安全 + // If return uses an Indirect statement, the variable may be + // destructed early, producing a dangling pointer. Assign the + // Indirect to a temporary variable; Ctor::Copy releases the + // Indirect, guaranteeing memory safety. $tmpVar = $this->genTmpVarName(); - // 必须提前声明变量,否则在末尾声明并 return 可能会被 gcc 优化掉 + // The variable must be declared up front; otherwise declaring it at + // the end and returning it could be optimized away by gcc. $this->addLocalVar($tmpVar, $returnType); $code = $tmpVar . ' = (' . $exprCode . ');' . PHP_EOL; - // 解析表达式后可能会插入语句,因此需要在末尾添加 return 语句,而不是直接返回 + // Parsing the expression may insert statements, so the return + // statement must be appended at the end rather than returned directly. $this->context->afterStmtLines[] = $this->getIndent() . 'return ' . $tmpVar . ';'; } else { $code = 'return ' . $exprCode . ';'; @@ -2715,7 +2751,8 @@ class CompilerBase implements PropertyAccessContext $classDef = $this->getClass($class); $methodDef = null; - // 递归查找,若子类中未定义方法,则尝试查找父类是否存在此方法 + // Search recursively: if the method is not defined in the child class, + // try to find it in the parent class. while (true) { if (!$classDef->hasMethod($method)) { if (!$classDef->extends) { @@ -2743,7 +2780,7 @@ class CompilerBase implements PropertyAccessContext if (!$this->checkAccessible($classDef, $methodDef->flags)) { $this->fatalError($expr, 'Method `' . $classDef->getNamespacedName() . '::' . $method . '()` is not accessible'); } - // 函数调用占位符,不是真实的函数调用 + // A function-call placeholder, not a real function call. if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { return false; } @@ -2767,7 +2804,8 @@ class CompilerBase implements PropertyAccessContext $classDef = $this->getClass($class); $originClassDef = $classDef; $constDef = null; - // 递归查找,若子类中未定义方法,则尝试查找父类是否存在此方法 + // Search recursively: if the constant is not defined in the child class, + // try to find it in the parent class. while (true) { if (!$classDef->hasConstant($const)) { if (!$classDef->extends) { @@ -3276,12 +3314,15 @@ class CompilerBase implements PropertyAccessContext } /** - * $GLOBALS['var'] 等价于 global $var; $var ,将字符串常量转为变量名称即可 - * 仅限于字面量字符串可以转为变量名称,其他则使用 php::global() 函数获取 + * Resolve a PHP function name to its native (compiled) name by trying + * every candidate form: absolute names, qualified names resolved through + * the class/namespace import table, unqualified names in the current + * namespace, and `use function` imports. Returns false when no compiled + * function matches. */ protected function findNativeFunction(string $funcName): string|false { - // 绝对命名空间的函数 + // Absolutely-qualified function name. if ($funcName[0] == '\\') { $funcName = ltrim($funcName, '\\'); $possibleFunctionNames = [$this->escapeName($funcName)]; @@ -3759,13 +3800,14 @@ class CompilerBase implements PropertyAccessContext $this->assertNotNativeObjectDynamicClassTarget($expr->class, $expr); } $ctorClassName = ''; - // 匿名类 + // Anonymous class. if ($expr->class instanceof Node\Stmt\Class_) { if ($expr->class->name === null) { $classDef = $expr->class; $className = $this->genAnonClassName(); $classDef->name = new Node\Identifier($className); - // 继承父类和接口可能是 use 的名称,需要转换成全限定名称 + // The inherited parent class and interfaces may be `use` names + // and need to be converted to fully-qualified names. if ($classDef->extends !== null) { $parentClass = $this->getNamespacedClassName($this->parseIdentifier($classDef->extends)); $classDef->extends = new Node\Name\FullyQualified($parentClass); @@ -3777,7 +3819,9 @@ class CompilerBase implements PropertyAccessContext } } $this->flattenEmbeddedClassTraits($classDef); - // 匿名类由根命名空间中的 eval 定义,内部导入的符号必须转为全限定名称。 + // Anonymous classes are defined by eval in the root namespace, + // so symbols imported inside them must be converted to + // fully-qualified names. $this->resolveAnonClassNames($classDef); $this->context->beforeStmtLines[] = 'static THREAD_LOCAL bool ' . $className . '_defined = false;'; $classCode = $this->genEmbeddedCode($classDef); @@ -4144,7 +4188,7 @@ class CompilerBase implements PropertyAccessContext protected function parseEval(Expr\Eval_ $expr): string { $this->assertExprCanBeUsedAsValue($expr->expr, 'eval operand'); - // 对 eval() 指令的 PHP 代码段禁止字面量优化 + // Disable literal-string optimization for the PHP code passed to eval(). $expr->expr->setAttribute('noLiteralString', true); $source = $this->isNativeObjectClass($this->detectClassOfExpr($expr->expr)) ? $this->parseExprToString($expr->expr) @@ -4239,7 +4283,8 @@ class CompilerBase implements PropertyAccessContext } /** - * 左值只能为变量、数组、对象属性、对象静态属性 + * The left value may only be a variable, array element, object property, + * or class static property. */ protected function checkLeftValue(NodeAbstract $expr): void { @@ -4282,7 +4327,8 @@ class CompilerBase implements PropertyAccessContext return $nativePresence; } } - // TypePHP 编译器不允许操作未定义的变量,PHP 的 isset($var) 可能 $var 未定义 + // The TypePHP compiler disallows operating on undefined variables; + // in PHP, isset($var) may be used with an undefined $var. $this->checkVarMustExist($node, $this->parseIdentifier($node)); $fn = $this->getChainedFunc($op); $expr = $node; @@ -4301,7 +4347,7 @@ class CompilerBase implements PropertyAccessContext // $getValue is true: fall through to use the chain+result mechanism, // which ensures the result type is TYPE_VAR (compatible with ternaries). } - // 单属性读取(非链式) + // Single property read (non-chained). if ($this->isPropertyFetch($expr) and $this->isVarExpr($expr->var) and $this->isIdExpr($expr->name)) { $prop = $this->parsePropertyFetch($expr); if ($this->isNativePropertyAccess($expr)) { @@ -4371,7 +4417,8 @@ class CompilerBase implements PropertyAccessContext $node->setAttribute('chainOpResult', $result); return $fn . '(' . $var . ', {' . implode(', ', $list) . '}, ' . $result . ')'; } else { - // toReference(var, {}) 返回空引用,空链时改用成员函数形式 + // toReference(var, {}) returns an empty reference; use the member + // function form instead when the chain is empty. if ($op === self::OP_REFVAL && empty($list)) { return $var . '.toReference()'; } @@ -4854,19 +4901,20 @@ class CompilerBase implements PropertyAccessContext if ($toType === Type::VAR or $fromType === Type::VAR) { return true; } - // 引用当前没有类型信息,按照 var 处理 + // References currently carry no type information, so treat them as var. if ($toType === Type::REF or $fromType === Type::REF) { return true; } - // 类型一致,可以互相赋值 + // Types are identical, so they can be assigned to each other. if ($toType === $fromType) { return true; } - // 原生类型可以互相转换,由 C++ 底层完成 + // Native types can be converted between each other, handled by the C++ layer. if ($this->isNativeType($toType) and $this->isNativeType($fromType)) { return true; } - // BigInt/BigFloat/Decimal 与原生类型之间可能发生隐式转换,允许重新赋值 + // Implicit conversions between BigInt/BigFloat/Decimal and native types + // are possible, so re-assignment is allowed. $bigTypes = [Type::BIGINT, Type::DECIMAL, Type::BIGFLOAT]; if (in_array($toType, $bigTypes, true) or in_array($fromType, $bigTypes, true)) { return true; @@ -4911,12 +4959,12 @@ class CompilerBase implements PropertyAccessContext $scopeClassDef = $this->getClass($this->functionDef->attributeFactoryScope); } } - // 私有方法,只能当前的类使用 + // Private methods can only be used by the current class. if ($flags & Modifiers::PRIVATE) { return $scopeClassDef !== null && $this->isSameClassName($declaringClass, $scopeClassDef->getNamespacedName(false)); } - // 保护方法,只能当前类和子类使用 + // Protected methods can only be used by the current class and its subclasses. if ($flags & Modifiers::PROTECTED) { if (!$scopeClassDef) { return false; @@ -4926,12 +4974,14 @@ class CompilerBase implements PropertyAccessContext $declaringClass ); } - // 类外部调用,只允许调用 public 方法 + // Calls from outside the class are only allowed for public methods. return true; } /** - * 沿继承链查找实际调用的构造函数,包括项目类继承的内部类构造函数。 + * Walk the inheritance chain to find the constructor that is actually + * invoked, including constructors of internal classes inherited by project + * classes. * * @return array{className: string, flags: int}|null */ diff --git a/src/Context/CompilationStateTrait.php b/src/Context/CompilationStateTrait.php index dcf83c2f..84f4f544 100644 --- a/src/Context/CompilationStateTrait.php +++ b/src/Context/CompilationStateTrait.php @@ -45,7 +45,7 @@ trait CompilationStateTrait $this->fatalError($var, 'Duplicate variable `$' . $var->name . '`'); } $this->context->staticVars[$name] = $type; - // 静态变量实际上是一个全局变量的引用 + // A static variable is actually a reference to a global variable. $globalVar = $this->escapeStaticVar($name); $this->addGlobalVar($globalVar, $type); return $globalVar; @@ -165,7 +165,7 @@ trait CompilationStateTrait } /** - * @param string $name 必须传入带有完整命名空间的类名,将会自动转义为 native name + * @param string $name Must be a fully qualified class name including the namespace; it will be automatically escaped to a native name. */ protected function hasFunction(string $name): bool { @@ -222,8 +222,8 @@ trait CompilationStateTrait protected function checkFunction(string $name): void { - // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 - // 跳过,稍后再处理 + // The function declaration was detected during the preprocessing stage but is not yet defined, + // meaning it is in the current file but appears in the wrong order. Skip it and handle it later. if (isset($this->symbolDeclInFile[$name]) and $this->symbolDeclInFile[$name] === $this->file and !$this->hasFunction($name)) { diff --git a/src/Entity/FunctionDef.php b/src/Entity/FunctionDef.php index 90aaad82..71aa1b4c 100644 --- a/src/Entity/FunctionDef.php +++ b/src/Entity/FunctionDef.php @@ -64,7 +64,7 @@ class FunctionDef public string $displayName = ''; /** - * @var string 必须是带有命名空间的完整类名 + * @var string Must be a fully qualified class name including the namespace */ public string $returnClass = ''; /** Whether a Native object return may be represented by nullptr. */ diff --git a/src/Extractor.php b/src/Extractor.php index e3238cfb..c9a52335 100644 --- a/src/Extractor.php +++ b/src/Extractor.php @@ -18,12 +18,12 @@ class Extractor } /** - * 提取函数定义. + * Extract function definitions. * - * @param string $filename 文件路径 - * @param array $prefixes 函数名前缀列表 + * @param string $filename File path + * @param array $prefixes List of function-name prefixes * - * @return array 函数列表 + * @return array List of functions */ public function extractFunctions(string $filename, array $prefixes = ['php_']): array { @@ -34,10 +34,10 @@ class Extractor $this->info("分析文件: {$filename}"); $this->info('函数前缀: ' . implode(', ', $prefixes)); - // 运行 ctags + // Run ctags. $tags = $this->runCtags($filename); - // 过滤和解析函数 + // Filter and parse functions. $functions = []; foreach ($tags as $tag) { if ($tag['kind'] !== 'function') { @@ -46,7 +46,7 @@ class Extractor $funcName = $tag['name'] ?? ''; - // 检查前缀 + // Check the prefix. $matched = false; foreach ($prefixes as $prefix) { if (str_starts_with($funcName, $prefix)) { @@ -59,7 +59,7 @@ class Extractor continue; } - // 解析函数详细信息 + // Parse the detailed function information. $funcInfo = $this->parseFunction($filename, $tag); if ($funcInfo) { $functions[] = $funcInfo; @@ -72,7 +72,7 @@ class Extractor } /** - * 批量提取多个文件. + * Extract functions from multiple files in bulk. */ public function extractFromFiles(array $files, array $prefixes = ['php_']): array { @@ -91,7 +91,7 @@ class Extractor } /** - * 检查 ctags 是否可用. + * Check whether ctags is available. */ private function checkCtags(): void { @@ -107,7 +107,7 @@ class Extractor } /** - * 运行 ctags 命令. + * Run the ctags command. */ private function runCtags(string $filename): array { @@ -123,7 +123,7 @@ class Extractor throw new \RuntimeException('ctags 执行失败'); } - // 解析 JSON 输出 + // Parse the JSON output. $tags = []; $lines = explode("\n", trim($output)); @@ -144,7 +144,7 @@ class Extractor } /** - * 解析单个函数的详细信息. + * Parse the detailed information of a single function. */ private function parseFunction(string $filename, array $tag): ?array { @@ -155,17 +155,17 @@ class Extractor return null; } - // 提取完整的函数签名 + // Extract the complete function signature. $signature = $this->extractSignature($filename, $lineNum, $funcName); if (empty($signature)) { return null; } - // 解析返回类型 + // Parse the return type. $returnType = $this->parseReturnType($signature, $funcName); - // 解析参数 + // Parse the parameters. $parameters = $this->parseParameters($signature, $funcName); return [ @@ -183,7 +183,7 @@ class Extractor } /** - * 从源文件中提取完整的函数签名. + * Extract the complete function signature from the source file. */ private function extractSignature(string $filename, int $lineNum, string $funcName): string { @@ -193,7 +193,7 @@ class Extractor return ''; } - // 从函数声明行开始收集,直到遇到 { 或 ; + // Collect lines starting from the function declaration until a { or ; is reached. $signatureLines = []; $maxLines = min($lineNum + 20, count($lines)); @@ -201,37 +201,37 @@ class Extractor $line = $lines[$i]; $signatureLines[] = $line; - // 检查是否到达函数体或声明结束 + // Check whether the function body or the end of the declaration has been reached. if (strpos($line, '{') !== false || strpos($line, ';') !== false) { break; } } - // 合并并清理 + // Join and clean up. $signature = implode(' ', $signatureLines); - // 移除 { 或 ; 之后的内容 + // Remove everything after the { or ;. $signature = preg_replace('/[{;].*$/', '', $signature); - // 合并多个空白字符 + // Collapse multiple whitespace characters. $signature = preg_replace('/\s+/', ' ', $signature); - // 清理首尾空白 + // Trim leading and trailing whitespace. return trim($signature); } /** - * 解析返回类型. + * Parse the return type. */ private function parseReturnType(string $signature, string $funcName): string { - // 匹配: <返回类型> <函数名>( + // Match: ( $pattern = '/^(.+?)\s+' . preg_quote($funcName, '/') . '\s*\(/'; if (preg_match($pattern, $signature, $matches)) { $returnType = trim($matches[1]); - // 移除可能的修饰符 + // Remove possible modifiers. $returnType = preg_replace('/\b(static|inline|extern|virtual|explicit)\b/', '', $returnType); $returnType = preg_replace('/\s+/', ' ', $returnType); $returnType = trim($returnType); @@ -243,11 +243,11 @@ class Extractor } /** - * 解析参数列表. + * Parse the parameter list. */ private function parseParameters(string $signature, string $funcName): array { - // 提取括号内的参数 + // Extract the parameters inside the parentheses. $pattern = '/' . preg_quote($funcName, '/') . '\s*\((.*?)\)/s'; if (!preg_match($pattern, $signature, $matches)) { @@ -256,12 +256,12 @@ class Extractor $paramsStr = trim($matches[1]); - // 空参数或 void + // Empty parameters or void. if (empty($paramsStr) || $paramsStr === 'void') { return []; } - // 分割参数(处理嵌套的模板和括号) + // Split the parameters (handling nested templates and parentheses). $params = $this->splitParameters($paramsStr); $parameters = []; @@ -282,7 +282,7 @@ class Extractor } /** - * 智能分割参数(处理嵌套的模板和括号). + * Intelligently split parameters (handling nested templates and parentheses). */ private function splitParameters(string $paramsStr): array { @@ -316,17 +316,17 @@ class Extractor } /** - * 解析单个参数. + * Parse a single parameter. */ private function parseParameter(string $param): ?array { $param = trim($param); - // 移除默认值 + // Remove the default value. $param = preg_replace('/\s*=\s*.*$/', '', $param); - // 尝试匹配: <类型> <名称> - // 支持复杂类型如: const char*, std::string&, int**, etc. + // Try to match: . + // Supports complex types such as: const char*, std::string&, int**, etc. if (preg_match('/^(.+?)\s+(\w+)\s*$/', $param, $matches)) { return [ 'type' => trim($matches[1]), @@ -334,7 +334,7 @@ class Extractor ]; } - // 只有类型,没有名称 + // Only a type, no name. return [ 'type' => $param, 'name' => '', @@ -342,7 +342,7 @@ class Extractor } /** - * 输出信息. + * Output an informational message. */ private function info(string $message): void { @@ -350,7 +350,7 @@ class Extractor } /** - * 输出警告. + * Output a warning. */ private function warn(string $message): void { @@ -358,7 +358,7 @@ class Extractor } /** - * 输出错误并退出. + * Output an error and exit. */ private function error(string $message): void { diff --git a/src/Generator/CallArgumentGenerator.php b/src/Generator/CallArgumentGenerator.php index 6e19fc8f..03c70f44 100644 --- a/src/Generator/CallArgumentGenerator.php +++ b/src/Generator/CallArgumentGenerator.php @@ -35,7 +35,7 @@ trait CallArgumentGenerator $hasNamedArg = false; $argNameIndex = $this->getFunctionArgNameIndex($functionDef); $variadicArgIndex = $this->getVariadicArgIndex($functionDef); - // 对命名参数进行重排 + // Reorder the named arguments into their declared positions foreach ($callArgs as $i => $arg) { if ($this->isPlaceholderExpr($arg)) { throw new PlaceHolder(); @@ -76,7 +76,7 @@ trait CallArgumentGenerator if ($deferTrailingDefaults && $variadicArgCount > 0) { $lastProvidedIndex = $variadicArgIndex; } - // 命名参数中间存在空洞,需要使用默认参数填充 + // Holes left between named arguments must be filled with default arguments foreach ($functionDef->argInfoList as $k => $argInfo) { if ($k < $parameterOffset) { continue; @@ -118,7 +118,8 @@ trait CallArgumentGenerator } } - // 函数只接受一个变长参数,且调用参数为空,直接传入空数组 + // If the function only accepts a single variadic parameter and the call + // supplies no arguments, pass an empty array directly if (count($sourceArgs) === 0 and count($functionDef->argInfoList) === $parameterOffset + 1 and $functionDef->argInfoList[$parameterOffset]->variadic) { @@ -203,7 +204,8 @@ trait CallArgumentGenerator } if ($className) { - // 动态调用类方法,无法判断参数是否为引用 + // For dynamically called class methods, whether the parameter is + // passed by reference cannot be determined if ($className === self::DYNAMIC_CALLED_CLASS) { return false; } @@ -216,7 +218,8 @@ trait CallArgumentGenerator return $param->isPassedByReference(); } - // 参数索引超出声明范围,检查最后一个参数是否为变长引用参数(如 &...$rest) + // The argument index exceeds the declared range; check whether the last + // parameter is a by-reference variadic parameter (e.g. &...$rest) $variadicParam = Reflection::getVariadicParameter($funcName, $className); return $variadicParam !== null && $variadicParam->isPassedByReference(); } @@ -492,7 +495,7 @@ trait CallArgumentGenerator $array = $this->parseIdentifier($arg->value->var); if ($array === 'GLOBALS') { $globalVar = $this->parseGlobalsArrayDimFetch($arg->value); - // 全局变量作为引用参数 + // Global variable passed as a by-reference argument if ($byRef) { $ref = $this->addTmpVar(Type::REF); $this->context->beforeStmtLines[] = $ref . ' = ' . $globalVar . '.toReference();'; @@ -749,8 +752,9 @@ trait CallArgumentGenerator } /** - * 展开 refval() 调用中的数组元素或对象属性,返回对应的 C++ 引用表达式。 - * 若为普通变量则返回 null,由调用方自行处理。 + * Expand an array element or object property inside a refval() call into its + * corresponding C++ reference expression. Returns null for a plain variable, + * which the caller then handles itself. */ protected function expandRefvalExpr(NodeAbstract $inner, Node\Arg $arg): ?string { @@ -777,27 +781,31 @@ trait CallArgumentGenerator } /** - * 仅用于动态调用的参数解析 + * Argument parsing used only for dynamic calls */ protected function parseArgRefVar(Node\Arg $arg, string $name): string { if (!$this->hasVar($name)) { - // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 + // For a by-reference parameter, an undefined variable may be passed; + // it is created immediately as a reference $this->addLocalVar($name, Type::REF); } elseif ($this->getVarType($name) === Type::REF) { return '&' . $name; } else { - // 本地变量,且是原生类型,则转为普通变量 + // A local variable of native type is converted to a plain variable if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) { $this->context->localVars[$name] = Type::VAR; } - // 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数 + // For a by-reference parameter, use a temporary variable as the reference + // and replace the actual argument with it $tmpVar = $this->genTmpVarName(); $this->addLocalVar($tmpVar, Type::REF); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; $name = $tmpVar; } - // 动态调用,参数列表是 Variant 类型而不是 Reference,必须使用 & 符号取地址,传递指针,以保持引用传递 + // For dynamic calls, the argument list is Variant rather than Reference, + // so the & operator must be used to take the address and pass a pointer + // in order to preserve pass-by-reference semantics return '&' . $name; } diff --git a/src/Generator/ClosureGenerator.php b/src/Generator/ClosureGenerator.php index 99428229..df24d589 100644 --- a/src/Generator/ClosureGenerator.php +++ b/src/Generator/ClosureGenerator.php @@ -285,7 +285,8 @@ trait ClosureGenerator $this->fatalError($useItem->var, 'Incorrect Closure use syntax, only variable names are allowed'); } if ($useItem->byRef) { - // 闭包的 use 语法,若为引用类型,可以就地创建变量 + // For a closure use clause, a by-reference capture may create + // the variable in place if it does not exist yet if (!isset($oriContext->localVars[$var]) && !isset($oriContext->staticVars[$var])) { $oriContext->localVars[$var] = Type::REF; diff --git a/src/Generator/ResourceFileGenerator.php b/src/Generator/ResourceFileGenerator.php index a663fb5a..7a1e8e96 100644 --- a/src/Generator/ResourceFileGenerator.php +++ b/src/Generator/ResourceFileGenerator.php @@ -3,11 +3,12 @@ namespace TypePhp\Generator; /** - * Windows 资源文件 (.rc) 生成器 + * Windows resource file (.rc) generator * - * 用于生成 Windows PE 资源文件,可将图标、版本信息等嵌入到 exe 中 + * Generates Windows PE resource files, embedding icons, version information, + * and other resources into the exe * - * 配置示例(在 project.yml 中): + * Configuration example (in project.yml): * * resource: * icon: path/to/icon.ico @@ -28,18 +29,18 @@ namespace TypePhp\Generator; * product-name: "My Product" * comments: "Built with TypePHP" * - * # manifest 与 resource 同级(可选,Windows 平台缺省不携带) + * # manifest sits at the same level as resource (optional; omitted by default on Windows) * manifest: path/to/app.manifest */ class ResourceFileGenerator { /** - * 资源配置 + * Resource configuration */ private array $config; /** - * 项目目录(用于解析相对路径) + * Project directory (used to resolve relative paths) */ private string $projectDir; @@ -50,7 +51,7 @@ class ResourceFileGenerator } /** - * 检查是否有任何资源配置 + * Check whether any resource is configured */ public function hasResource(): bool { @@ -60,7 +61,7 @@ class ResourceFileGenerator } /** - * 获取图标文件的绝对路径 + * Get the absolute path of the icon file */ public function getIconPath(): ?string { @@ -73,7 +74,7 @@ class ResourceFileGenerator } /** - * 获取 manifest 文件的绝对路径 + * Get the absolute path of the manifest file */ public function getManifestPath(): ?string { @@ -86,21 +87,21 @@ class ResourceFileGenerator } /** - * 解析相对/绝对路径为绝对路径 + * Resolve a relative/absolute path into an absolute path */ private function resolvePath(string $path): string { - // 如果是绝对路径,直接使用 + // If it is already an absolute path, use it as-is if (preg_match('/^[A-Za-z]:\\\\|^\//', $path)) { return $path; } - // 相对路径,基于项目目录解析 + // Otherwise resolve the relative path against the project directory return $this->projectDir . DIRECTORY_SEPARATOR . $path; } /** - * 生成 .rc 资源文件内容 + * Generate the contents of the .rc resource file */ public function generate(): string { @@ -109,15 +110,15 @@ class ResourceFileGenerator $content .= '// DO NOT EDIT - This file is auto-generated' . PHP_EOL; $content .= PHP_EOL; - // 告诉 rc.exe 此文件使用 UTF-8 编码,避免中文乱码 + // Tell rc.exe this file is UTF-8 encoded to avoid garbled Chinese text $content .= '#pragma code_page(65001)' . PHP_EOL; $content .= PHP_EOL; - // 包含 Windows 版本信息头文件 + // Include the Windows header for version information $content .= '#include ' . PHP_EOL; $content .= PHP_EOL; - // Manifest 资源(Windows 清单文件,如 UAC、DPI 感知等) + // Manifest resource (Windows application manifest, e.g. UAC, DPI awareness, etc.) $manifestPath = $this->getManifestPath(); if ($manifestPath) { $manifestPathRc = str_replace('\\', '/', $manifestPath); @@ -126,17 +127,17 @@ class ResourceFileGenerator $content .= PHP_EOL; } - // 图标资源 + // Icon resource $iconPath = $this->getIconPath(); if ($iconPath) { - // 使用正斜杠,Windows RC 编译器更兼容 + // Use forward slashes for better compatibility with the Windows RC compiler $iconPathRc = str_replace('\\', '/', $iconPath); $content .= '// Icon Resource' . PHP_EOL; $content .= 'MAINICON ICON "' . addslashes($iconPathRc) . '"' . PHP_EOL; $content .= PHP_EOL; } - // 版本信息 + // Version information $versionInfo = $this->config['version-info'] ?? []; if (!empty($versionInfo)) { $content .= $this->generateVersionInfo($versionInfo); @@ -146,7 +147,7 @@ class ResourceFileGenerator } /** - * 生成版本信息块 + * Generate the version information block */ private function generateVersionInfo(array $info): string { @@ -165,16 +166,17 @@ class ResourceFileGenerator $content .= 'FILESUBTYPE ' . ($info['file-subtype'] ?? 'VFT2_UNKNOWN') . PHP_EOL; $content .= 'BEGIN' . PHP_EOL; - // StringFileInfo 块 + // StringFileInfo block $content .= ' BLOCK "StringFileInfo"' . PHP_EOL; $content .= ' BEGIN' . PHP_EOL; - // 语言代码页(040904b0 = 英文/UTF-8,配合 #pragma code_page(65001) 正确显示中文) + // Language code page (040904b0 = English/UTF-8, used with #pragma code_page(65001) + // so Chinese text renders correctly) $langCodepage = $info['lang-codepage'] ?? '040904b0'; $content .= ' BLOCK "' . $langCodepage . '"' . PHP_EOL; $content .= ' BEGIN' . PHP_EOL; - // 字符串值 + // String values $stringFields = [ 'company-name' => 'CompanyName', 'file-description' => 'FileDescription', @@ -195,19 +197,20 @@ class ResourceFileGenerator } } - // 如果没有设置 FileVersion,从 file-version 字段自动填入 + // If FileVersion was not set, it is auto-filled from the file-version field if (!isset($info['file-version-str']) && $fileVersion) { - // 已在上面通过 file-version 键处理 + // Already handled above via the file-version key } $content .= ' END' . PHP_EOL; $content .= ' END' . PHP_EOL; - // VarFileInfo 块 + // VarFileInfo block $content .= ' BLOCK "VarFileInfo"' . PHP_EOL; $content .= ' BEGIN' . PHP_EOL; - // 0x0409 = English(US),1200 = Unicode(UTF-16) - // 配合 StringFileInfo 中的 040904b0 代码页,确保中文在 UTF-8 源文件中正确编码 + // 0x0409 = English(US), 1200 = Unicode(UTF-16) + // Combined with the 040904b0 code page in StringFileInfo, this ensures + // Chinese text in the UTF-8 source file is encoded correctly $content .= ' VALUE "Translation", 0x0409, 1200' . PHP_EOL; $content .= ' END' . PHP_EOL; @@ -217,31 +220,31 @@ class ResourceFileGenerator } /** - * 将版本号格式化为逗号分隔的格式(1,0,0,0) - * 支持以下输入格式: + * Format a version number into comma-separated form (1,0,0,0). + * Supported input formats: * - "1.0.0.0" → "1,0,0,0" * - "1,0,0,0" → "1,0,0,0" - * - "v1052" → "1052,0,0,0" (去掉 v 前缀) + * - "v1052" → "1052,0,0,0" (strips the leading "v") * - "1.0" → "1,0,0,0" */ private function formatVersionDots(string $version): string { - // 去掉 v/V 前缀(如 v1052 → 1052) + // Strip a leading v/V prefix (e.g. v1052 → 1052) $version = ltrim($version, 'vV'); - // 如果已经是逗号分隔格式,直接返回 + // Return as-is if it is already comma-separated if (str_contains($version, ',')) { return $version; } - // 用点号分隔 + // Split on dots $parts = explode('.', $version); - // 确保每个部分都是数字(过滤掉非数字字符) + // Keep only digits in each part (filter out non-numeric characters) foreach ($parts as $i => $part) { $parts[$i] = preg_replace('/[^0-9]/', '', $part) ?: '0'; } - // 确保恰好有4个部分 + // Ensure exactly four parts while (count($parts) < 4) { $parts[] = '0'; } @@ -250,7 +253,7 @@ class ResourceFileGenerator } /** - * 生成 resource.h 头文件内容(可选,供 C++ 代码引用资源 ID) + * Generate the resource.h header contents (optional, lets C++ code reference resource IDs) */ public function generateHeader(): string { diff --git a/src/Installer/LibPhpInstaller.php b/src/Installer/LibPhpInstaller.php index 2f082bf4..1c2e7e55 100644 --- a/src/Installer/LibPhpInstaller.php +++ b/src/Installer/LibPhpInstaller.php @@ -176,10 +176,11 @@ final class LibPhpInstaller private function currentConfigureOptions(): string { - // 优先使用 PHP_BINARY -i 的 Configure Command:输出保留每个参数的 - // 引号,能正确处理 `CFLAGS=-g -O2` 这类含空格的值。而 - // `php-config --configure-options` 会丢失引号,导致含空格的值被 - // 错误拆分(例如 `-O2` 被当作独立参数传给 configure)。 + // Prefer the "Configure Command:" output from `PHP_BINARY -i`, which preserves + // the quoting of each argument and can therefore handle values containing spaces + // such as `CFLAGS=-g -O2`. In contrast, `php-config --configure-options` drops the + // quotes, causing space-containing values to be split incorrectly (for example, + // `-O2` being passed to configure as a separate argument). $info = $this->capture([PHP_BINARY, '-n', '-i']); if (preg_match('/^Configure Command =>\s*(.+)$/mi', $info, $match)) { $words = PhpBuildConfiguration::parseShellWords(trim($match[1])); @@ -189,8 +190,9 @@ final class LibPhpInstaller return implode(' ', array_map('escapeshellarg', $words)); } - // 后备:php-config --configure-options。PPA 的多版本 PHP 共用 - // /usr 前缀,因此 PHP_HOME=/usr 时必须优先 php-config8.x。 + // Fallback: php-config --configure-options. On PPA multi-version installations + // several PHP versions share the /usr prefix, so when PHP_HOME=/usr the + // versioned php-config8.x must be preferred. $versionedPhpConfig = $this->sourcePhpDir . '/bin/php-config' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; if ($this->sourcePhpDir !== null && is_executable($versionedPhpConfig)) { diff --git a/src/Metadata/Constants.php b/src/Metadata/Constants.php index c2da960f..0e796950 100644 --- a/src/Metadata/Constants.php +++ b/src/Metadata/Constants.php @@ -188,7 +188,7 @@ class Constants 'description' => 'Run the compiled binary after build', 'noValue' => true, ], - // 内部开发选项,用于定位特定行的翻译问题,请勿写入用户文档 + // Internal development option used to locate translation issues on a specific line. Do not write it into user documentation. 'debug-line' => [ 'longPrefix' => 'debug-line', 'description' => 'Enable debug line', @@ -305,10 +305,10 @@ class Constants ]; /** - * MSVC 编译器警告屏蔽列表 - * 这些警告来自 Windows SDK 和 PHP SDK 头文件,都是编译器噪音,不影响功能 + * MSVC compiler warning suppression list. + * These warnings come from Windows SDK and PHP SDK headers and are compiler noise that does not affect functionality. * - * @var array 键为警告编号,值为说明 + * @var array key is the warning number, value is the description */ public const array MSVC_SUPPRESSED_WARNINGS = [ '4244' => '类型转换可能丢失数据 (int -> smaller type)', diff --git a/src/Optimizer/FuncCallOptimizer.php b/src/Optimizer/FuncCallOptimizer.php index f78f2ff9..fe2ae690 100644 --- a/src/Optimizer/FuncCallOptimizer.php +++ b/src/Optimizer/FuncCallOptimizer.php @@ -233,8 +233,9 @@ trait FuncCallOptimizer } } - // 检测参数中使用的变量是否已定义,若变量不存在则回退到动态调用路径 - // 动态路径中的 parseCallArgs() 会给出明确的错误信息 + // Check whether the variables used in the arguments are defined; if a variable + // does not exist, fall back to the dynamic call path, where parseCallArgs() + // produces a clear error message. foreach ($expr->args as $arg) { if (!$arg instanceof Node\Arg) { continue; @@ -269,7 +270,7 @@ trait FuncCallOptimizer protected function dispatchFuncCall(string $name, Node\Expr\FuncCall $expr, array $config): string|false { - // 命名参数 / unpack(...)展开需要运行时处理,回退到动态调用路径 + // Named arguments and unpack (...) expansion require runtime handling; fall back to the dynamic call path. foreach ($expr->args as $arg) { if ($arg->name !== null || $arg->unpack) { return false; diff --git a/src/Parser/ArrayExpressionTrait.php b/src/Parser/ArrayExpressionTrait.php index c0486b80..36fda31b 100644 --- a/src/Parser/ArrayExpressionTrait.php +++ b/src/Parser/ArrayExpressionTrait.php @@ -18,7 +18,7 @@ trait ArrayExpressionTrait protected function parseArray(Expr\Array_ $node): string { $items = $node->items; - // 优化代码风格,空数组直接返回{},否则会产生一些空洞内容 + // Optimize code style: return {} directly for an empty array, otherwise it would produce empty entries if (count($items) === 0) { return Type::ARRAY . '{}'; } @@ -55,7 +55,7 @@ trait ArrayExpressionTrait } } - // 存在混合键,则需要拆分为多行插入 + // Mixed keys are present, so split the insertion into multiple statements if ($hasReference or $hasUnpack or $hasVarKey or ($hasNextInsert && $hasKey) or ($hasIntKey and $hasStrKey)) { return $this->parseArrayMixed($node); } @@ -82,7 +82,8 @@ trait ArrayExpressionTrait } /** - * 获取包含路径 + * Resolve a `$GLOBALS[...]` array-dim fetch to its static slot when the key + * is a known global name, or to a php::global() lookup otherwise. */ protected function parseGlobalsArrayDimFetch(Expr\ArrayDimFetch $node): string @@ -270,7 +271,7 @@ trait ArrayExpressionTrait { $tmpVar = $this->genTmpVarName(); $this->addLocalVar($tmpVar, Type::ARRAY); - // 释放临时变量,避免修改数组产生数组复制操作 + // Release the temporary variable to avoid array copies when the array is modified $this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.clean();'; $items = $node->items; diff --git a/src/Parser/AssignOpTrait.php b/src/Parser/AssignOpTrait.php index d0aca8a6..470490d1 100644 --- a/src/Parser/AssignOpTrait.php +++ b/src/Parser/AssignOpTrait.php @@ -153,7 +153,7 @@ trait AssignOpTrait $this->addLocalVar($tmpVar, Type::VAR); } - // 翻转赋值链 + // Reverse the assignment chain $chain = array_reverse($chain); $list = []; @@ -525,7 +525,7 @@ trait AssignOpTrait return $copyAssign; } } - // 类型推断,获取对象的类名,如果不是对象则返回空字符串 + // Infer the type and obtain the object's class name; return an empty string for non-objects $rightClass = $this->detectClassOfExpr($right); $markNativeObjectNonNull = $this->context->scopeLevel <= 1 && !$this->hasScopeGlobalVar($var) @@ -548,7 +548,7 @@ trait AssignOpTrait $this->fatalError($right, "Cannot assign native object `{$rightClass}` to `{$leftClass}`"); } } - // 右值是一个对象,已获得类的名称,左值必须与右值的类一致 + // The right-hand value is an object and its class name is known; the left-hand side must match the right-hand side's class if ($rightClass) { if (!$this->hasVar($var)) { if ($this->isNativeObjectClass($rightClass)) { @@ -641,7 +641,7 @@ trait AssignOpTrait } } } - // 变量第一次被赋值,确定其类型,由于 PHP 的变量作用域是 function 级的,在 for/while 块中声明的变量,可以在块外使用 + // On first assignment the variable's type is determined. PHP variable scope is function-level, so variables declared in for/while blocks remain usable outside the block if (!$this->hasVar($var)) { $finalVarType = $this->getNormalAssignType($type); $finalVarType = $this->isNativeType($finalVarType) ? $this->getNativeType($finalVarType) : $finalVarType; @@ -944,9 +944,9 @@ trait AssignOpTrait } /** * $count[$r] -= 1; - * 需要转为下面语句: + * must be lowered to the following statements: * $tmp_var = $count[$r] - 1; - * $count[$r] = $tmp_var;. + * $count[$r] = $tmp_var; */ $isGlobals = $this->isVarExpr($node->var->var) && $node->var->var->name === 'GLOBALS'; $type = $isGlobals ? Type::VAR : $this->detectVarType($node->var); diff --git a/src/Parser/BinaryOpTrait.php b/src/Parser/BinaryOpTrait.php index 3212cb40..a97f653c 100644 --- a/src/Parser/BinaryOpTrait.php +++ b/src/Parser/BinaryOpTrait.php @@ -24,7 +24,7 @@ trait BinaryOpTrait $this->assertExprCanBeUsedAsValue($left, 'binary operand'); $this->assertExprCanBeUsedAsValue($right, 'binary operand'); - // 运算逻辑,优先转为数字 + // Arithmetic logic: convert to a numeric type first when possible $leftExpr = $this->parseOrderedBinaryOperand($left); $rightExpr = $this->parseOrderedBinaryOperand($right); @@ -927,7 +927,7 @@ trait BinaryOpTrait protected function parseCompareExpr(NodeAbstract $expr): string { $this->assertExprCanBeUsedAsValue($expr, 'comparison operand'); - // PHPX 与 bool 值比较会出现重载错误,所以需要转换成 bool 值 + // Comparing PHPX values with bool causes an overload error, so convert them to bool first if ($this->isScalarBool($expr)) { return $this->getBoolValue($expr); } diff --git a/src/Parser/ForeachTrait.php b/src/Parser/ForeachTrait.php index 5fc77a9e..235157de 100644 --- a/src/Parser/ForeachTrait.php +++ b/src/Parser/ForeachTrait.php @@ -220,8 +220,8 @@ trait ForeachTrait } /** - * 为了兼容已有代码,默认不使用原生类型,而是将整数和浮点数作为 php 变量处理 - * 原生 int/float/bool 类型,是不支持自动转换的,例如如果 int 计算超过最大值后,会自动转为 float,除法若不能除尽,则会转为 float - * 某些情况下高性能计算,可能需要使用原生类型,使用 $a = std::int(0) 来显式地使用原生类型 + * For backward compatibility, native types are not used by default; integers and floats are treated as php variables. + * Native int/float/bool types do not support automatic conversion. For example, an int computation that exceeds its maximum value is promoted to float, and a division that does not divide evenly becomes float. + * In some cases high-performance computation may need native types; use `$a = std::int(0)` to explicitly opt into native types. */ } diff --git a/src/Parser/FunctionCallTrait.php b/src/Parser/FunctionCallTrait.php index c3ef736d..1b573516 100644 --- a/src/Parser/FunctionCallTrait.php +++ b/src/Parser/FunctionCallTrait.php @@ -177,7 +177,7 @@ trait FunctionCallTrait ) { $this->fatalError($expr, 'Native ABI functions cannot be converted to Zend closures'); } - // 函数调用占位符,不是真实的函数调用 + // Function call placeholder, not a real function call if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { return $this->genPlaceHolder($this->identifierToStr($expr->name)); } @@ -195,7 +195,7 @@ trait FunctionCallTrait return $this->genPlaceHolder($this->identifierToStr($expr->name)); } } - // 动态调用的函数,转换函数名为带有命名空间的全限定名称 + // For dynamically dispatched functions, convert the function name to its fully qualified name including the namespace $name = $this->getNamespacedFuncName($name); $this->checkInternalFunctionArgCount($name, $expr); $code = $this->parseFuncCallWithOptimizer($name, $expr); diff --git a/src/Parser/MethodCallTrait.php b/src/Parser/MethodCallTrait.php index 959123fc..0f6ec71e 100644 --- a/src/Parser/MethodCallTrait.php +++ b/src/Parser/MethodCallTrait.php @@ -252,7 +252,7 @@ trait MethodCallTrait } $nativeFunc = $this->getNativeMethod($expr, $class, $method); - // 存在 Native 类,但是没有找到方法,可能是动态调用 + // A Native class exists but the method was not found; this may be a dynamic call if (!$nativeFunc) { if ($this->hasClass($class) and $this->getNativeMethod($expr, $class, '__call', false)) { throw new DynamicCall(); @@ -261,7 +261,7 @@ trait MethodCallTrait $fullMethodName = $this->getOverrideMethodName($class, $method); - // 存在子类同名方法,尝试去虚化 + // A subclass declares a method with the same name, so try to devirtualize if ($this->isOverrideMethod($fullMethodName)) { if (!$this->canDevirtualize($object, $class, $method)) { return false; @@ -414,7 +414,7 @@ trait MethodCallTrait if (empty($expr->args)) { return 'this_.call(' . $methodPtr . ')'; } - // 传入方法名与父类名,以便在按引用参数检测时解析方法签名 + // Pass the method name and parent class so the method signature can be resolved when detecting by-reference arguments return 'this_.call(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $method, $parentClass) . ')'; } @@ -465,10 +465,10 @@ trait MethodCallTrait if ($this->isTypedObject($object)) { $class = $this->getObjectType($object); } elseif ($object === 'this_') { - // $this 在构造函数/方法中静态类型为当前类,便于解析抽象方法等按引用参数签名 + // $this is statically typed as the current class inside a constructor/method, so abstract methods and other by-reference parameter signatures can be resolved $class = $this->classDef !== null ? $this->classDef->getNamespacedName(false) : $this->class; } else { - // 接口和抽象类类型的变量没有具体对象类型,仍可从声明签名解析按引用参数。 + // Variables of interface or abstract-class type have no concrete object type, but by-reference parameters can still be resolved from the declared signature. $class = $this->getDeclaredObjectType($object); } } @@ -591,7 +591,7 @@ trait MethodCallTrait . $this->parseCallArgs($expr->args) . ')'; } - // 可转为原生调用的 MethodCall + // Method calls that can be lowered to a native call if (($this->isVarExpr($expr->var) || $materializedNativeReceiver) and $this->isNamedMethod($expr->name)) { $type = $this->getVarType($object); if ($class !== '' && $this->isNativeObjectClass($class)) { @@ -647,9 +647,9 @@ trait MethodCallTrait return self::PREFIX . $nativeFunc . '(' . $receiver . ', ' . $this->parseNativeCallArgs($expr->args, $nativeFunc) . ')'; } - // 引用参数允许方法调用:有class信息走原生调用,无class信息走动态调用 + // Method calls are allowed on references: use a native call when class info is available, otherwise a dynamic call if (!$this->checkArgType($type, Type::OBJECT) and $type !== Type::REF) { - // 非对象类型可使用内置方法 + // Non-object types can use built-in methods $fn = $this->findUniversalMethodAnyType($type, $methodName); if ($fn) { if ($type === Type::STREAM) { @@ -705,7 +705,7 @@ trait MethodCallTrait } } - // 表达式返回值也可使用内置方法:fn()->method(), $obj->fn()->method(), Foo::fn()->method(), $obj->prop->method() + // Expression results can also use built-in methods: fn()->method(), $obj->fn()->method(), Foo::fn()->method(), $obj->prop->method() if (!$this->isVarExpr($expr->var) and $this->isNamedMethod($expr->name)) { $type = $this->detectTypeOfExpr($expr->var); if ($type === Type::VOID) { @@ -929,7 +929,7 @@ trait MethodCallTrait ); } $placeHolder = $this->genArray([Symbol::getCalledClass(), $methodPtr]); - // 用于在按引用参数检测时解析方法签名(late static binding 在当前类层级中解析) + // Used to resolve the method signature when detecting by-reference arguments (late static binding is resolved within the current class hierarchy) $rtFunc = $method; $rtClass = $this->getFullClassName(); } else { @@ -974,7 +974,7 @@ trait MethodCallTrait } catch (PlaceHolder) { return $this->genPlaceHolder($this->genArray($callScope)); } - // 在方法定义中使用了当前类的方法 self::method(),依然应该传递 this_ 指针 + // When a method definition calls a current-class method via self::method(), the this_ pointer must still be passed if ($this->methodDef and $self) { $object = 'this_'; } else { diff --git a/src/Parser/PropertyAccessTrait.php b/src/Parser/PropertyAccessTrait.php index f821b092..c553fd09 100644 --- a/src/Parser/PropertyAccessTrait.php +++ b/src/Parser/PropertyAccessTrait.php @@ -595,13 +595,13 @@ trait PropertyAccessTrait } if ($def->class === '' or $this->isAbstractClass($def->class) or $this->isInterface($def->class) or !$this->hasClass($def->class)) { - // 属性 declared class 若是接口、抽象类或动态类,当前属性布局优化无法静态确认最终对象类型。 - // 不在这里 fatal;后续 wrapObjectPropertyAssignTypeCheck() 会在需要时插入运行时检查。 + // If the property's declared class is an interface, abstract class, or dynamic class, the current property layout optimization cannot statically determine the final object type. + // Do not report a fatal error here; wrapObjectPropertyAssignTypeCheck() inserts a runtime check later when needed. return; } $rightClass = $this->detectClassOfExpr($right); - // TODO 静态编译阶段无法获得准确的类型,需要在运行时检查 + // TODO: the exact type cannot be determined at the static compilation stage; a runtime check is required if ($rightClass === '') { return; } diff --git a/src/Parser/SwitchTrait.php b/src/Parser/SwitchTrait.php index 794391c1..b851b54a 100644 --- a/src/Parser/SwitchTrait.php +++ b/src/Parser/SwitchTrait.php @@ -38,7 +38,7 @@ trait SwitchTrait $var_def .= $type . ' ' . $tmp_var . ' = ' . $condExpr . ';' . PHP_EOL; $var_def .= $this->formatCapturedStmtLines($condAfterStmts); - // 保存作用域,switch 可能会解析失败,在这个过程中会增加变量,需重置 + // Save the scope; switch parsing may fail partway and add variables in the process, so it must be reset $localVars = $this->context->localVars; $code = $this->parseBeforeStmtLines() . PHP_EOL; diff --git a/src/Platform/PlatformBase.php b/src/Platform/PlatformBase.php index 10a1d678..91dd8e91 100644 --- a/src/Platform/PlatformBase.php +++ b/src/Platform/PlatformBase.php @@ -3,98 +3,98 @@ namespace TypePhp\Platform; /** - * 平台抽象基类 - * 定义所有平台必须实现的接口 + * Abstract platform base class. + * Defines the interface every platform must implement. */ abstract class PlatformBase { /** - * 获取平台名称 + * Get the platform name. */ abstract public function getName(): string; /** - * 判断是否为当前平台 + * Determine whether this is the current platform. */ abstract public function isCurrent(): bool; /** - * 获取编译器包含路径参数 + * Get the compiler include-path flags. */ abstract public function getIncludeFlags(array $includePaths): string; /** - * 获取链接器库路径参数 + * Get the linker library-path flags. */ abstract public function getLibraryPathFlags(array $libraryPaths): string; /** - * 获取链接库参数 + * Get the link-library flags. */ abstract public function getLibraryFlags(array $libraries): string; /** - * 获取文件扩展名 + * Get the object file extension. */ abstract public function getObjectExtension(): string; /** - * 获取可执行文件扩展名 + * Get the executable file extension. */ abstract public function getExecutableExtension(): string; /** - * 获取动态库扩展名 + * Get the shared library extension. */ abstract public function getSharedLibraryExtension(): string; /** - * 获取生成共享库所需的链接器选项 + * Get the linker options required to produce a shared library. */ abstract public function getSharedLinkFlag(): string; /** - * 获取无控制台程序的子系统选项;不适用的平台返回空字符串 + * Get the subsystem options for a console-less program; platforms where this does not apply return an empty string. */ abstract public function getSubsystemOptions(bool $noConsole): string; /** - * 获取平台 C 运行库链接配置;不适用的平台返回空字符串 + * Get the platform C runtime library link configuration; platforms where this does not apply return an empty string. */ abstract public function getCrtConfig(): string; /** - * 获取路径分隔符 + * Get the path separator. */ abstract public function getPathSeparator(): string; /** - * 获取该平台默认使用的 C++ 编译器命令 + * Get the default C++ compiler command for this platform. */ abstract public function getDefaultCompiler(): string; /** - * 获取 PHP 安装目录 + * Get the PHP installation directory. */ abstract public function getPhpDir(): string; /** - * 构建 PHP 包含路径 + * Build the PHP include paths. */ abstract public function buildPhpIncludePaths(string $phpDir): array; /** - * 构建 PHP 库路径 + * Build the PHP library paths. */ abstract public function buildPhpLibPaths(string $phpDir): array; /** - * 检测 PHP 库文件 + * Detect the PHP library files. */ abstract public function detectPhpLibs(string $phpDir): array; /** - * 获取指定构建模式的目标文件扩展名 + * Get the target file extension for the given build mode. */ public function getTargetExtension(string $buildMode): string { @@ -104,7 +104,7 @@ abstract class PlatformBase } /** - * 获取构建前的运行库检查告警 + * Get the runtime library check warnings issued before building. */ public function getBuildLibraryWarnings( string $phpDir, @@ -141,7 +141,7 @@ abstract class PlatformBase } /** - * 当前平台是否适合使用 pcntl_fork 并行编译 + * Whether this platform is suitable for parallel compilation using pcntl_fork. */ public function supportsPcntlParallelCompile(): bool { @@ -154,7 +154,7 @@ abstract class PlatformBase } /** - * 规范化路径 + * Normalize a path. */ public function normalizePath(string $path): string { @@ -162,7 +162,7 @@ abstract class PlatformBase } /** - * 组合路径 + * Join path components. */ public function joinPath(string ...$parts): string { @@ -196,15 +196,15 @@ abstract class PlatformBase } /** - * 获取默认的 RPATH 路径列表(仅 macOS 需要) - * - * @param string|null $phpxDir phpx 目录路径 - * @param string|null $phpDir PHP 目录路径 - * @return array RPATH 路径数组 + * Get the default RPATH path list (only needed on macOS). + * + * @param string|null $phpxDir phpx directory path + * @param string|null $phpDir PHP directory path + * @return array RPATH path array */ public function getDefaultRpaths(?string $phpxDir = null, ?string $phpDir = null): array { - // 默认返回空数组,由子类重写 + // Return an empty array by default; subclasses may override. return []; } } diff --git a/src/Platform/UnixPlatform.php b/src/Platform/UnixPlatform.php index 9d7ef36b..2a1b4731 100644 --- a/src/Platform/UnixPlatform.php +++ b/src/Platform/UnixPlatform.php @@ -3,8 +3,8 @@ namespace TypePhp\Platform; /** - * Unix-like 平台基类(Linux, macOS) - * 包含 GCC/Clang 通用标志语法的共享实现 + * Base class for Unix-like platforms (Linux, macOS). + * Contains the shared implementation of common GCC/Clang flag syntax. */ abstract class UnixPlatform extends PlatformBase { @@ -107,9 +107,10 @@ abstract class UnixPlatform extends PlatformBase return $phpDir; } - // Ubuntu/PPA 多版本环境下 php8.4 与 php-config8.4 并存,而 - // php-config 可能被 update-alternatives 指向其它版本。优先依据 - // PHP_BINARY 的版本后缀定位版本化 php-config,避免 ABI 错配。 + // On Ubuntu/PPA multi-version installations, php8.4 and php-config8.4 coexist, + // while the unversioned php-config may be pointed at another version by + // update-alternatives. Prefer locating the versioned php-config from the + // version suffix of PHP_BINARY to avoid an ABI mismatch. $versionedConfig = $this->findVersionedPhpConfig(dirname(realpath(PHP_BINARY) ?: PHP_BINARY)); if ($versionedConfig !== null) { $prefix = $this->getPhpConfigValue($versionedConfig, '--prefix'); @@ -144,7 +145,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 获取 RPATH 选项 + * Get the RPATH options. */ public function getRpathOptions(array $paths): string { @@ -161,7 +162,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 获取 PIC 选项 + * Get the PIC option. */ public function getPicFlag(): string { @@ -169,7 +170,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 构建 PHP 包含路径(使用 php-config 动态获取) + * Build the PHP include paths (obtained dynamically via php-config). */ public function buildPhpIncludePaths(string $phpDir): array { @@ -209,7 +210,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 查找 php-config 可执行文件 + * Locate the php-config executable. */ protected function findPhpConfig(string $phpDir): ?string { @@ -273,14 +274,14 @@ abstract class UnixPlatform extends PlatformBase } } - // 依次返回第一个与当前 PHP 主次版本匹配的候选 + // Return the first candidate whose major/minor version matches the current PHP. foreach (array_unique($candidates) as $config) { if ($this->phpConfigMatchesCurrentPhp($config)) { return $config; } } - // 存在候选但版本均不匹配时给出明确错误 + // Report a clear error when candidates exist but none matches the version. if ($candidates !== []) { $this->reportPhpConfigVersionMismatch($candidates[0]); } @@ -296,7 +297,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 校验 php-config 的主次版本号是否与当前运行的 PHP 一致。 + * Verify that php-config's major/minor version matches the currently running PHP. */ private function phpConfigMatchesCurrentPhp(string $phpConfig): bool { @@ -346,7 +347,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 构建 PHP 库路径 + * Build the PHP library paths. */ public function buildPhpLibPaths(string $phpDir): array { @@ -355,7 +356,7 @@ abstract class UnixPlatform extends PlatformBase } /** - * 检测 PHP 库文件 + * Detect the PHP library files. */ public function detectPhpLibs(string $phpDir): array { diff --git a/src/Platform/Windows.php b/src/Platform/Windows.php index 3527c972..208c586c 100644 --- a/src/Platform/Windows.php +++ b/src/Platform/Windows.php @@ -3,22 +3,22 @@ namespace TypePhp\Platform; /** - * Windows 平台实现 + * Windows platform implementation. */ class Windows extends PlatformBase { /** - * PHP 库文件信息 + * PHP library file information. */ private array $phpLibs = []; /** - * 是否为 ZTS 模式 + * Whether this is a ZTS build. */ private bool $isZts = false; /** - * PHP SDK 路径 + * PHP SDK path. */ private string $phpSdkPath = ''; @@ -137,7 +137,7 @@ class Windows extends PlatformBase } /** - * 获取 PHP 库文件列表 + * Get the list of PHP library files. */ public function getPhpLibs(): array { @@ -145,7 +145,7 @@ class Windows extends PlatformBase } /** - * 判断是否为 ZTS 模式 + * Determine whether this is a ZTS build. */ public function isZts(): bool { @@ -153,7 +153,7 @@ class Windows extends PlatformBase } /** - * 获取 PHP SDK 路径 + * Get the PHP SDK path. */ public function getPhpSdkPath(): string { @@ -161,7 +161,7 @@ class Windows extends PlatformBase } /** - * 获取 Windows 子系统选项 + * Get the Windows subsystem options. */ public function getSubsystemOptions(bool $noConsole): string { @@ -173,7 +173,7 @@ class Windows extends PlatformBase } /** - * 获取 CRT 库配置 + * Get the CRT library configuration. */ public function getCrtConfig(): string { @@ -232,7 +232,7 @@ class Windows extends PlatformBase } /** - * 获取调试选项 + * Get the debug options. */ public function getDebugOptions(bool $debugInfo): string { @@ -254,7 +254,7 @@ class Windows extends PlatformBase } /** - * 构建 PHP SDK 包含路径 + * Build the PHP SDK include paths. */ public function buildPhpSdkIncludePaths(string $phpDir): array { @@ -265,7 +265,7 @@ class Windows extends PlatformBase $paths = [$phpSdkInclude]; - // 添加子目录 + // Add the subdirectories. $subDirs = ['main', 'Zend', 'TSRM', 'ext']; foreach ($subDirs as $subDir) { $subPath = $phpSdkInclude . '\\' . $subDir; @@ -278,18 +278,18 @@ class Windows extends PlatformBase } /** - * 构建 PHP SDK 库路径 + * Build the PHP SDK library paths. */ public function buildPhpSdkLibPaths(string $phpDir): array { $paths = []; - // 优先从 SDK/lib 读取 + // Prefer reading from SDK/lib. $phpLib = $phpDir . '\\SDK\\lib'; if (is_dir($phpLib)) { $paths[] = $phpLib; } else { - // 备选:尝试直接从 lib 目录 + // Fallback: try the lib directory directly. $phpLibAlt = $phpDir . '\\lib'; if (is_dir($phpLibAlt)) { $paths[] = $phpLibAlt; @@ -300,7 +300,7 @@ class Windows extends PlatformBase } /** - * 检测 PHP lib 文件并决定 ZTS/NTS 模式 + * Detect the PHP lib files and decide the ZTS/NTS mode. */ public function detectPhpLibs(string $phpDir): array { diff --git a/src/Preprocessor.php b/src/Preprocessor.php index f824e9a7..8c91e1ce 100644 --- a/src/Preprocessor.php +++ b/src/Preprocessor.php @@ -180,7 +180,7 @@ class Preprocessor extends CompilerBase $sorter = new StringSort(); $fileDeps = []; - // 构建依赖关系图 + // Build the dependency graph foreach ($this->symbolCallInFile as $file => $symbols) { $deps = []; foreach ($symbols as $symbol) { @@ -198,7 +198,7 @@ class Preprocessor extends CompilerBase $sortedFiles = $sorter->sort(); - // 添加未参与依赖管理的文件(非 stub 文件且不在已排序列表中) + // Append files that do not participate in dependency management (non-stub files not present in the sorted list) foreach ($list as $file) { if (!$this->isStubFile($file) and !in_array($file, $sortedFiles)) { $sortedFiles[] = $file; @@ -237,7 +237,7 @@ class Preprocessor extends CompilerBase $info = pathinfo($cppFile); $ext = $this->getPlatform()->getObjectExtension(); - // 保持与 cppFile 相同的路径分隔符 + // Keep the same path separator as cppFile $normalizedFile = str_replace('\\', '/', $cppFile); $normalizedMiscDir = str_replace('\\', '/', $this->getPhpxDir() . '/src/misc/'); if (str_starts_with($normalizedFile, $normalizedMiscDir)) { @@ -719,7 +719,7 @@ class Preprocessor extends CompilerBase foreach ($functionCalls as $call) { if ($call->name instanceof Node\Name) { - // 内置函数不参与依赖管理 + // Internal functions do not participate in dependency management $funcName = strtolower($call->name->toString()); if (!$this->isInternalFunction($funcName)) { $this->symbolCallInFile[$this->file][] = $funcName; @@ -741,7 +741,7 @@ class Preprocessor extends CompilerBase } } } - // 依赖去重 + // Deduplicate dependencies $this->symbolCallInFile[$this->file] = array_unique($this->symbolCallInFile[$this->file]); } @@ -846,7 +846,7 @@ class Preprocessor extends CompilerBase if ($this->stubFile && $this->stubImportLibrary === '' && !$param->type) { throw new \RuntimeException('No type for ' . $phpName); } - // 构造方法属性定义语法(Constructor Property Promotion) + // Constructor property promotion syntax if ($param->isPromoted()) { if (!$this->classDef or !$this->methodDef or $this->methodDef->name !== '__construct') { $this->fatalError($param, 'Promoted properties are not supported'); @@ -910,7 +910,7 @@ class Preprocessor extends CompilerBase $this->lowerArgumentDefault($param, $argInfo); } } elseif ($param->variadic) { - // 变长参数可以视为空数组默认值 + // A variadic parameter can be treated as an empty-array default value $argInfo->default = '{}'; $argInfo->defaultValue = new Node\Expr\Array_(); } @@ -960,7 +960,7 @@ class Preprocessor extends CompilerBase // Local stubs define C++ native functions and require an explicit ABI return type. // Generated external stubs may preserve an untyped PHP declaration as php::Var. if ($this->stubFile && $this->stubImportLibrary === '' && !$v->returnType) { - // 以下魔术方法都不能声明返回值类型 __construct()/__destruct()/__clone() + // The following magic methods must not declare a return type: __construct()/__destruct()/__clone() if (($this->method and !in_array($this->method, ['__construct', '__destruct', '__clone'])) or !$this->method) { $name = $this->class ? $this->class . '::' . $v->name : $v->name; $this->fatalError($v, 'The return type of the function `' . $name . '` must be specified'); @@ -997,7 +997,7 @@ class Preprocessor extends CompilerBase if ($nullableNativeReturn !== null) { [$returnType, $class] = $nullableNativeReturn; } - // 构造、析构、克隆方法不能有返回值 + // Constructor, destructor, and clone methods cannot have a return value if ($this->method and in_array($this->method, ['__construct', '__destruct', '__clone'])) { $returnType = Type::VOID; } @@ -1077,7 +1077,7 @@ class Preprocessor extends CompilerBase $this->fatalError($v, 'Zend-backed constructors cannot accept or return native objects'); } - // main 函数,返回值必须为 void 类型,参数必须为空或者 argc, argv 两个参数 + // The main function must return void and take either no parameters or the two parameters argc and argv if (!$this->class and !$this->namespace and $fnName === self::ENTRY_FUNCTION) { if (count($v->params) > 0) { if (count($v->params) != 2) { @@ -1158,7 +1158,7 @@ class Preprocessor extends CompilerBase } $this->fatalError($v, "Duplicate function `{$name}`"); } - // 禁止重定义内置函数 + // Forbid redefining built-in functions if (!$this->methodDef and $this->isInternalFunction($name)) { $this->fatalError($v, "The function `{$name}` is a built-in function and cannot be redefined"); } @@ -1241,7 +1241,7 @@ class Preprocessor extends CompilerBase $this->symbolCallInFile[$this->file][] = $parentClassLower; } $this->classDef->extends = $this->parentClass; - // 是否继承了内置类 + // Whether it inherits from an internal class $this->classDef->inheritedFromInternalClass = $this->isInternalClass($parentClassLower); } @@ -2146,11 +2146,11 @@ class Preprocessor extends CompilerBase $fullMethodNameLower = strtolower($fullMethodName); $fullClassNameLower = strtolower($fullClassName); - // 检查子类是否已覆盖此方法(子类先于父类被预处理的情况) + // Check whether a subclass already overrides this method (when the subclass is preprocessed before the parent) $isOverridden = $this->isMethodOverriddenInSubClasses($fullClassNameLower, $this->method); $this->classMethodOverride[$fullMethodNameLower] = $isOverridden; - // 查找父类是否有同名方法,递归向上标记父类方法已被覆盖 + // Find whether a parent class has a method with the same name, and recursively mark the parent method as overridden while (($parentClass = $this->symbols->parent($fullClassNameLower)) !== '') { $parentMethodLower = strtolower($parentClass . '::' . $this->method); if (isset($this->classMethodOverride[$parentMethodLower])) { @@ -2182,7 +2182,7 @@ class Preprocessor extends CompilerBase } /** - * 递归检查所有子类(及子类的子类)是否已定义了同名方法,用于处理子类先于父类被预处理的情况。 + * Recursively check whether any subclass (and its subclasses) has defined a method with the same name; handles the case where a subclass is preprocessed before its parent. */ private function isMethodOverriddenInSubClasses(string $classNameLower, string $method): bool { @@ -2400,7 +2400,7 @@ class Preprocessor extends CompilerBase // use THello1, THello2 { // hello as hello3; // } - // 未指定 trait,将添加所有 trait 的别名映射,在预处理阶段无法获取 trait 的方法列表 + // No trait specified: add alias mappings for all traits, since the trait's method list is unavailable during preprocessing $traits = $traitUse->traits; } else { $traits[] = $adaptation->trait; @@ -2409,9 +2409,9 @@ class Preprocessor extends CompilerBase $traitName = $this->getNamespacedClassName($this->parseIdentifier($trait)); $methodName = $adaptation->method->toString(); /* - * 例如: + * For example: * use TraitA { TraitA::method as newMethod} - * 这表示 TraitA::method() 会被重命名为 TraitA::newMethod() + * This means TraitA::method() is renamed to TraitA::newMethod() */ $aliases[$this->getFullMethodName($traitName, $methodName)][] = [ 'newName' => $adaptation->newName ? $adaptation->newName->toString() : $methodName, @@ -2425,9 +2425,9 @@ class Preprocessor extends CompilerBase } $methodName = $adaptation->method->toString(); /* - * 例如: + * For example: * use TraitA { TraitA::method insteadof TraitB} - * 这表示 TraitB::method() 将会被忽略,真正执行的是 TraitA::method() + * This means TraitB::method() is ignored, and TraitA::method() is actually executed */ foreach ($adaptation->insteadof as $trait2) { $traitName = $this->getNamespacedClassName($this->parseIdentifier($trait2)); diff --git a/src/PythonTools/Converter/PythonAstLoader.php b/src/PythonTools/Converter/PythonAstLoader.php index 6d10a2f7..155073e0 100644 --- a/src/PythonTools/Converter/PythonAstLoader.php +++ b/src/PythonTools/Converter/PythonAstLoader.php @@ -5,8 +5,8 @@ namespace TypePhp\PythonTools\Converter; use RuntimeException; /** - * 非 final:测试可子类化注入预制 AST 或模拟解析失败, - * 见 phpunit/src/PythonTools/PythonAstLoaderTest.php。 + * Intentionally non-final so tests can subclass it to inject a canned AST or simulate a parse failure; + * see phpunit/src/PythonTools/PythonAstLoaderTest.php. */ class PythonAstLoader { diff --git a/src/PythonTools/Converter/PythonToTypePhpConverter.php b/src/PythonTools/Converter/PythonToTypePhpConverter.php index 348215b2..829bf09a 100644 --- a/src/PythonTools/Converter/PythonToTypePhpConverter.php +++ b/src/PythonTools/Converter/PythonToTypePhpConverter.php @@ -15,7 +15,7 @@ final class PythonToTypePhpConverter /** @var array */ private array $definedFunctions = []; - /** @var array 被装饰的函数:调用点必须经变量间接调用装饰结果 */ + /** @var array Decorated functions: call sites must invoke the decorator result indirectly through a variable */ private array $decoratedFunctions = []; /** @var array */ @@ -53,12 +53,12 @@ final class PythonToTypePhpConverter foreach ($tree['body'] ?? [] as $node) { if (in_array($node['_type'] ?? '', ['Assign', 'AnnAssign', 'AugAssign'], true)) { - // 纯注解声明没有运行期值,不登记为模块全局变量 + // An annotation-only declaration has no runtime value, so it is not registered as a module global. $annotationOnly = ($node['_type'] ?? '') === 'AnnAssign' && ($node['value'] ?? null) === null; if (!$annotationOnly) { $targets = ($node['_type'] ?? '') === 'Assign' ? ($node['targets'] ?? []) : [$node['target'] ?? []]; foreach ($targets as $target) { - // 解构赋值展开为其中的名称元素 + // A destructuring assignment expands into its individual name elements. $elements = in_array($target['_type'] ?? '', ['Tuple', 'List'], true) ? ($target['elts'] ?? []) : [$target]; @@ -77,7 +77,7 @@ final class PythonToTypePhpConverter $name = (string) $node['name']; $this->definedFunctions[$name] = true; if (($node['decorator_list'] ?? []) !== []) { - // 装饰结果绑定到模块级变量,函数内调用需要 global 注入 + // The decorator result is bound to a module-level variable, so calls inside functions need a global injection. $this->decoratedFunctions[$name] = true; $this->moduleGlobals[$name] = true; } @@ -108,7 +108,7 @@ final class PythonToTypePhpConverter if ($this->moduleGlobals !== []) { $lines[] = $this->line('global ' . implode(', ', $this->variables(array_keys($this->moduleGlobals))) . ';'); } - // 装饰器重绑定先于其他顶层语句执行,使后续调用拿到装饰结果 + // Decorator rebinding runs before other top-level statements so that subsequent calls observe the decorated result. foreach ($functions as $function) { foreach ($this->decoratorRebindings($function) as $rebinding) { $lines[] = $this->line($rebinding); @@ -202,7 +202,7 @@ final class PythonToTypePhpConverter } /** - * Python 的 main 函数与 TypePHP 入口点冲突,重命名为 main_。 + * Python's main function conflicts with the TypePHP entry point, so it is renamed to main_. */ private function functionName(string $name): string { @@ -210,8 +210,8 @@ final class PythonToTypePhpConverter } /** - * 生成装饰器的重绑定语句(Python 自底向上应用装饰器)。 - * 装饰结果存入同名模块变量,调用点经变量间接调用。 + * Generate the rebinding statements for a function's decorators (Python applies decorators bottom-up). + * The decorated result is stored in a module variable of the same name, and call sites invoke it indirectly through that variable. * * @param array $function @return list */ @@ -233,7 +233,7 @@ final class PythonToTypePhpConverter /** @param array $node */ private function decoratorCallable(array $node): string { - // @dec(args):装饰器工厂,先求值再调用其返回值 + // @dec(args): a decorator factory; evaluate it first, then call its return value. if (($node['_type'] ?? '') === 'Call') { return $this->call($node); } @@ -312,7 +312,7 @@ final class PythonToTypePhpConverter $parts[] = match ($element['_type'] ?? '') { 'Name' => $this->variable((string) $element['id']), 'Attribute', 'Subscript' => $this->target($element), - // PHP 的 list 赋值不支持展开,嵌套元组的元素仍是 PyObject 无法直接解构 + // PHP list assignment does not support spreading, and nested tuple elements remain PyObject and cannot be destructured directly. 'Starred' => $this->unsupported($owner, 'starred destructuring is not supported'), default => $this->unsupported($owner, 'nested destructuring is not supported'), }; @@ -337,7 +337,7 @@ final class PythonToTypePhpConverter { $target = $this->target($node['target']); $operator = $node['op']['_type'] ?? ''; - // PHP 没有 //= 与 @=,展开为对应的运算符函数调用 + // PHP has no //= or @= operators, so these expand into the corresponding operator function calls. if ($operator === 'FloorDiv' || $operator === 'MatMult') { $function = $operator === 'FloorDiv' ? 'python\\operator\\floordiv' : 'python\\operator\\matmul'; return [$this->line($target . ' = ' . $function . '(' . $target . ', ' . $this->expression($node['value']) . ');')]; @@ -530,7 +530,7 @@ final class PythonToTypePhpConverter { $targets = []; $walk = function (array $target) use (&$walk, &$targets, $node): void { - // del (a, b) / del [a, b] 逐项展开 + // del (a, b) / del [a, b] expands element by element. if (in_array($target['_type'] ?? '', ['Tuple', 'List'], true)) { foreach ($target['elts'] ?? [] as $element) { $walk($element); @@ -585,7 +585,7 @@ final class PythonToTypePhpConverter if (($function['_type'] ?? '') === 'Name') { $name = (string) $function['id']; if (isset($this->decoratedFunctions[$name])) { - // 装饰结果绑定在同名变量上,必须经变量间接调用 + // The decorator result is bound to a variable of the same name, so it must be invoked indirectly through that variable. $callable = $this->variable($name); } elseif (isset($this->importedSymbols[$name])) { $symbol = $this->importedSymbols[$name]; diff --git a/src/Resolver/MagicMethodDetector.php b/src/Resolver/MagicMethodDetector.php index f4644a6d..9da0ad6b 100644 --- a/src/Resolver/MagicMethodDetector.php +++ b/src/Resolver/MagicMethodDetector.php @@ -201,7 +201,7 @@ trait MagicMethodDetector } } - // 重建 params 字符串,使 C++ 函数签名使用 auto-fill 后的类型 + // Rebuild the params string so the C++ function signature uses the auto-filled types $list = []; foreach ($fnDef->argInfoList as $argInfo) { if ($argInfo->variadic) { diff --git a/src/Resolver/NameResolutionTrait.php b/src/Resolver/NameResolutionTrait.php index 4c21e5a4..177295dd 100644 --- a/src/Resolver/NameResolutionTrait.php +++ b/src/Resolver/NameResolutionTrait.php @@ -69,12 +69,12 @@ trait NameResolutionTrait } /** - * 将 trait 方法参数中的类名 Name 节点升级为 Name\FullyQualified。 - * 对于已由 parseTypeDecl() 解析的限定名(含 \),直接升级节点类型; - * 对于尚未解析的非限定名(如 NullableType 内层,parseTypeDecl 返回 TYPE_VAR 跳过了解析), - * 先通过 useAliases/useNamespaces 解析再升级。 - * gen_stub.php 的 SimpleType::fromNode() 依赖 isFullyQualified() 判断是否需要再次解析, - * 若不升级为 FullyQualified,在上下文丢失后会被错误地追加当前 namespace 前缀。 + * Upgrade the class-name Name node in a trait method parameter to Name\FullyQualified. + * For qualified names (containing \) already resolved by parseTypeDecl(), upgrade the node type directly; + * for unresolved unqualified names (such as the inner type of a NullableType, which parseTypeDecl skips by returning TYPE_VAR), + * resolve them via useAliases/useNamespaces first and then upgrade. + * gen_stub.php's SimpleType::fromNode() relies on isFullyQualified() to decide whether to re-resolve; + * if the name is not upgraded to FullyQualified, the current namespace prefix is wrongly appended once the context is lost. */ protected function upgradeToFullyQualifiedName(?NodeAbstract $type): ?NodeAbstract { @@ -130,7 +130,7 @@ trait NameResolutionTrait } /** - * 函数名称处理,补齐 namespace + * Process the function name and prepend the namespace when required. */ public function getNamespacedFuncName(string $funcName): string { @@ -144,7 +144,7 @@ trait NameResolutionTrait } /** - * @param string $class 一定是带有命名空间的完整类名 + * @param string $class must be a fully qualified class name including the namespace */ protected function resolveTypeDecl(?NodeAbstract $type, int $what): array { @@ -155,17 +155,17 @@ trait NameResolutionTrait protected function parseTypeDecl(?NodeAbstract $type, int $what, string &$class): string { - // 未定义类型视为 var (mixed, any) + // An undefined type is treated as var (mixed, any) if ($type === null) { return Type::VAR; } if ($type instanceof UnionType || $type instanceof NullableType || $type instanceof IntersectionType) { - // 复杂类型静态阶段统一按 mixed/var 处理,运行时再由 typeCheck 兜底。 + // Complex types are uniformly treated as mixed/var at the static stage; the runtime typeCheck provides the fallback. return Type::VAR; } else { $typeName = $this->parseIdentifier($type); $typeNameLower = strtolower($typeName); - // 属性和类常量的类型不能声明为 void/never ,只有返回值可以 + // Property and class-constant types cannot be declared void/never; only return types can if ($what !== self::DECL_TYPE_OF_RETURN and ($typeNameLower === 'void' or $typeNameLower === 'never')) { $this->fatalError($type, 'The type `void`/`never` is allowed only for return type'); } elseif (isset($this->zendTypeMap[$typeNameLower])) { @@ -179,12 +179,12 @@ trait NameResolutionTrait } $class = $this->classDef->extends; } elseif ($typeName === 'static') { - // static 类无法在编译期获取 + // The static class cannot be determined at compile time $class = ''; } else { $class = $this->getNamespacedClassName($typeName); } - // Trait 在注入 class 需要使用完整类名 + // When a trait is injected into a class, the fully qualified class name is required if ($class and $this->classDef and $this->classDef->trait) { $type->name = $class; } diff --git a/src/Resolver/PropertyAccessResolver.php b/src/Resolver/PropertyAccessResolver.php index e53858b1..18a5266b 100644 --- a/src/Resolver/PropertyAccessResolver.php +++ b/src/Resolver/PropertyAccessResolver.php @@ -70,7 +70,7 @@ final class PropertyAccessResolver while (true) { $classDef = $this->compiler->getClassDef($findClass); if ($classDef === null) { - // 非编译单元内的类:尝试按内置类的声明属性解析(offset 缓存) + // Class outside the compilation unit: attempt to resolve it by the internal class's declared property (offset cache) return $this->resolveInternalClassProperty($expr, $property, $findClass, $class, $scope, $static); } @@ -160,11 +160,11 @@ final class PropertyAccessResolver } /** - * 解析 PHP 内置类的声明属性,使其可以进入稳定属性 offset 缓存。 + * Resolve the declared property of a PHP internal class so it can enter the stable property offset cache. * - * 仅处理反射可见的声明属性:动态属性、魔术属性(__get/__set)反射不可见, - * 返回 null 回退到按名字符串查找路径。内置类在 MINIT 注册、进程级存活, - * 其声明属性的 offset 终身不变,缓存安全。 + * Only declared properties visible to reflection are handled: dynamic properties and magic properties (__get/__set) are not visible to reflection, + * so return null to fall back to the by-name string lookup path. Internal classes are registered at MINIT and live for the whole process, + * so the offset of their declared properties never changes and caching is safe. */ private function resolveInternalClassProperty( NodeAbstract $expr, @@ -182,7 +182,7 @@ final class PropertyAccessResolver return null; } $propRef = $ref->getProperty($property); - // PHP 8.4 属性钩子必须由引擎调用,offset 直读会绕过钩子,回退字符串路径 + // PHP 8.4 property hooks must be invoked by the engine; reading the offset directly would bypass the hook, so fall back to the string path if ($propRef->hasHooks()) { return null; } @@ -209,8 +209,8 @@ final class PropertyAccessResolver $this->fatal($expr, "Cannot access private property `{$property}` of class `{$displayClass}`"); } - // 复合类型(union/intersection)的运行时检查结构依赖 AST 构建, - // 无法从反射便捷还原,回退字符串路径以保证类型安全 + // The runtime check structure for composite types (union/intersection) depends on the AST, + // which cannot be conveniently reconstructed from reflection, so fall back to the string path to preserve type safety $propType = $propRef->getType(); if ($propType !== null && !$propType instanceof \ReflectionNamedType) { return null; diff --git a/src/Resolver/Reflection.php b/src/Resolver/Reflection.php index 1eb2ff3f..55da4cc8 100644 --- a/src/Resolver/Reflection.php +++ b/src/Resolver/Reflection.php @@ -188,8 +188,8 @@ class Reflection } /** - * 当参数索引超出声明范围时,尝试将最后一个参数作为变长参数(...$rest)获取。 - * 返回变长参数对象或 null。 + * When the parameter index exceeds the declared range, try to obtain the last parameter as a variadic parameter (...$rest). + * Returns the variadic parameter object, or null. */ public static function getVariadicParameter(string $funcName, string $className = ''): ?\ReflectionParameter { diff --git a/src/Symbol/SymbolRepository.php b/src/Symbol/SymbolRepository.php index d86c5d38..ee461ae6 100644 --- a/src/Symbol/SymbolRepository.php +++ b/src/Symbol/SymbolRepository.php @@ -9,12 +9,13 @@ use TypePhp\Entity\InterfaceDef; final class SymbolRepository { /** - * 存储所有函数、类方法的定义,key 是 native name,命名空间需要转为 `_`,并且必须为小写 + * Stores the definitions of all functions and class methods. The key is the native name: + * the namespace must be converted to `_` and the result must be lowercase. * @var array */ private array $functions = []; /** - * key 类名,包含命名空间 + * Keyed by class name, including the namespace. * @var array */ private array $classes = []; diff --git a/src/Translator.php b/src/Translator.php index dac9b883..57fb2b8a 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -80,7 +80,7 @@ class Translator extends Preprocessor protected array $argInfoHeaderFiles = []; protected array $registerSymbols = []; - // Windows 资源文件配置(图标、版本信息等) + // Windows resource file configuration (icon, version info, etc.) protected array $resourceConfig = []; protected array $globalHeaders = [ 'cstring', @@ -112,8 +112,9 @@ class Translator extends Preprocessor $this->preprocessArgvAdvanced(); $this->climate->arguments->parse(); - // 只读取命令行参数,不立即应用(等待 YAML 解析后再应用) - // 这样可以确保优先级:命令行 > YAML > 默认值 + // Only read the command-line arguments here; do not apply them yet + // (they are applied after YAML parsing). This preserves the priority: + // command line > YAML > defaults. $this->internalFunctions = []; foreach (get_defined_functions()['internal'] as $functionName) { $function = Reflection::getFunction($functionName); @@ -133,13 +134,13 @@ class Translator extends Preprocessor exit(0); } - // 提前处理 --no-color,确保后续所有输出均为无颜色模式 + // Handle --no-color early so all subsequent output is colorless. if ($this->climate->arguments->defined('no-color')) { $this->climate->forceAnsiOff(); } - // 检测操作系统、编译器以及 Windows 平台的 PHP lib 文件 + // Detect the OS, the compiler, and (on Windows) the PHP lib files. $this->detectPlatform(); } @@ -152,7 +153,8 @@ class Translator extends Preprocessor $constants = []; foreach ($groups as $groupName => $group) { - // 编译器进程中的用户常量属于被编译程序的运行时状态,不能在静态阶段展开。 + // User constants in the compiler process belong to the compiled + // program's runtime state and must not be expanded in the static phase. if (strcasecmp((string) $groupName, 'user') === 0 || Reflection::isTypePhpExtension($groupName) || !is_array($group)) { @@ -166,7 +168,7 @@ class Translator extends Preprocessor } /** - * 检测操作系统、编译器以及 Windows 平台的 PHP lib 文件 + * Detect the OS, the compiler, and (on Windows) the PHP lib files. */ protected function detectPlatform(): void { @@ -295,43 +297,45 @@ class Translator extends Preprocessor } /** - * 应用命令行参数(在 YAML 解析后调用,确保命令行参数优先级最高) + * Apply command-line arguments (called after YAML parsing so command-line + * arguments take the highest priority). */ protected function applyCommandLineArguments(): void { $this->applyPhpVersionCommandLineArgument(); - // 优化级别 + // Optimization level if ($this->climate->arguments->defined('optimize')) { $this->optimizeLevel = $this->climate->arguments->get('optimize'); } - // 构建模式 + // Build mode if ($this->climate->arguments->defined('mode')) { $this->setBuildMode($this->climate->arguments->get('mode')); } - // 调试行号 + // Debug line number if ($this->climate->arguments->defined('debug-line')) { $this->debugLine = intval($this->climate->arguments->get('debug-line')); } - // 最大并行任务数 + // Maximum number of parallel jobs if ($this->climate->arguments->defined('job')) { $this->maxJob = intval($this->climate->arguments->get('job')); } - // 调试模式 + // Debug mode if ($this->climate->arguments->defined('debug')) { $this->debug = true; } - // 禁用字面量字符串优化 + // Disable literal string optimization if ($this->climate->arguments->defined('no-literal-strings')) { $this->noLiteralStrings = true; } - // 启用性能分析(需强制重编译 misc 文件以确保 PPROF_ON 宏生效,仅 Linux 支持) + // Enable profiling (forces recompilation of misc files so the PPROF_ON + // macro takes effect; Linux only) if ($this->climate->arguments->defined('profile')) { if (!$this->isLinux()) { $this->climate->error('--profile is only supported on Linux (requires gperftools)'); @@ -340,12 +344,12 @@ class Translator extends Preprocessor $this->enableProfiler = true; } - // 禁用进度条 + // Disable the progress bar if ($this->climate->arguments->defined('no-progress')) { $this->noProgress = true; } - // 隐藏控制台窗口 + // Hide the console window if ($this->climate->arguments->defined('no-console')) { $this->noConsole = true; } @@ -355,27 +359,27 @@ class Translator extends Preprocessor $this->sanitize = $this->climate->arguments->get('sanitize'); } - // C++ 标准版本 + // C++ standard version if ($this->climate->arguments->defined('cxx-std')) { $this->cxxStd = $this->climate->arguments->get('cxx-std'); } - // 目标 CPU 指令集 + // Target CPU instruction set if ($this->climate->arguments->defined('march')) { $this->march = $this->climate->arguments->get('march'); } - // 交叉编译目标平台 + // Cross-compilation target platform if ($this->climate->arguments->defined('target-platform')) { $this->targetPlatform = $this->climate->arguments->get('target-platform'); } - // 输出文件名/路径 + // Output file name/path if ($this->climate->arguments->defined('output')) { $this->setOutputPath($this->climate->arguments->get('output')); } - // 构建目录 + // Build directory if ($this->climate->arguments->defined('build-dir')) { $buildDir = $this->climate->arguments->get('build-dir'); if (!empty($buildDir)) { @@ -383,35 +387,39 @@ class Translator extends Preprocessor } } - // 干运行模式 + // Dry-run mode if ($this->climate->arguments->defined('dry')) { $this->dryRun = true; } - // 用户自定义 C++ include 路径(直接从 argv 解析以支持多值) + // User-defined C++ include paths (parsed directly from argv to support + // multiple values) if ($this->hasRepeatableArgvFlag(['-I', '--include-path'])) { $this->userIncludePaths = $this->parseRepeatableArgv(['-I', '--include-path']); } - // 用户自定义预处理器宏(直接从 argv 解析以支持多值) + // User-defined preprocessor macros (parsed directly from argv to support + // multiple values) if ($this->hasRepeatableArgvFlag(['-D', '--define'])) { $this->userDefines = $this->parseRepeatableArgv(['-D', '--define']); } - // 链接时优化 + // Link-time optimization if ($this->climate->arguments->defined('lto')) { $this->enableLto = true; } - // clang-format 代码格式化(默认关闭,需显式 --format 开启) + // clang-format code formatting (disabled by default; requires explicit --format) if ($this->climate->arguments->defined('format')) { $this->enableCodeFormattingIfAvailable('--format'); } - // 用户自定义链接库(直接从 argv 解析以支持多值) + // User-defined link libraries (parsed directly from argv to support + // multiple values) if ($this->hasRepeatableArgvFlag(['-l', '--link-lib'])) { $this->linkLibs = $this->parseRepeatableArgv(['-l', '--link-lib']); } - // 用户自定义库搜索路径(直接从 argv 解析以支持多值) + // User-defined library search paths (parsed directly from argv to support + // multiple values) if ($this->hasRepeatableArgvFlag(['-L', '--link-path'])) { $this->linkPaths = $this->parseRepeatableArgv(['-L', '--link-path']); } @@ -426,25 +434,26 @@ class Translator extends Preprocessor } /** - * 从原始 $argv 中解析可重复参数,支持 -X val 和 --long val 两种形式。 - * CLImate 的 multiple 选项只能保留最后一个值,因此需要手动解析。 + * Parse repeatable arguments from the raw $argv, supporting both the + * "-X val" and "--long val" forms. CLImate's "multiple" option only keeps + * the last value, so these must be parsed manually. * - * @param string[] $flags 要匹配的标志列表,如 ['-I', '--include-path'] - * @return string[] 收集到的所有值 + * @param string[] $flags Flags to match, e.g. ['-I', '--include-path'] + * @return string[] All collected values */ protected function parseRepeatableArgv(array $flags): array { global $argv; $values = []; for ($i = 1; $i < count($argv); $i++) { - // 精确匹配标志(如 -I, --include-path) + // Exact flag match (e.g. -I, --include-path) if (in_array($argv[$i], $flags, true) && isset($argv[$i + 1]) && $argv[$i + 1] !== '' && $argv[$i + 1][0] !== '-') { $values[] = $argv[$i + 1]; - $i++; // 跳过值 + $i++; // Skip the value } - // 合并形式:-I/path 或 --include-path=/path + // Combined form: -I/path or --include-path=/path elseif (!$this->isLongFlagWithEquals($argv[$i], $flags, $values)) { - // 检查短标志合并:-I/path + // Check short-flag combined form: -I/path foreach ($flags as $flag) { if (strlen($flag) === 2 && $flag[0] === '-') { $short = substr($flag, 1); @@ -485,7 +494,7 @@ class Translator extends Preprocessor } /** - * 处理 --flag=value 格式的长标志 + * Handle long flags in the --flag=value form. */ private function isLongFlagWithEquals(string $arg, array $flags, array &$values): bool { @@ -551,7 +560,8 @@ class Translator extends Preprocessor } else { $this->save($cppCode, $cppFile); } - // 生成 stub 文件,依赖 convert 阶段的 use 等信息 + // Generate the stub file, which depends on the use statements + // and other info collected during the convert phase. $this->genStubFile($this->file); return $cppCode === '' ? null : $cppFile; } catch (Redo $e) { @@ -583,8 +593,8 @@ class Translator extends Preprocessor } /** - * 初始化新的 Platform 和 Backend 抽象层 - * 这是一个渐进式迁移,保持向后兼容 + * Initialize the new Platform and Backend abstraction layers. + * This is an incremental migration that preserves backward compatibility. */ protected function initializeNewArchitecture(): void { @@ -592,7 +602,7 @@ class Translator extends Preprocessor $platform = $this->platform ?? PlatformFactory::create(); $this->platform = $platform; - // 自动检测平台和编译器 + // Auto-detect the platform and compiler $result = CompilerFactory::autoDetect($this->cppCompiler, $platform); $this->platform = $result['platform']; $this->compilerBackend = $result['compiler']; @@ -601,7 +611,7 @@ class Translator extends Preprocessor "Initialized new architecture: {$this->platform->getName()} + {$this->compilerBackend->getName()}" ); } catch (\Exception $e) { - // 如果初始化失败,回退到旧逻辑 + // Fall back to the legacy logic if initialization fails $this->climate->warning( "Failed to initialize new architecture: {$e->getMessage()}. Using legacy mode." ); @@ -611,14 +621,14 @@ class Translator extends Preprocessor } /** - * 设置 C++ 编译器(从配置文件读取) + * Set the C++ compiler (read from the config file). */ public function setCppCompiler(string $compiler): void { $this->cppCompiler = $compiler; $this->climate->info("Using compiler from config: {$this->cppCompiler}"); - // 重新初始化 Backend + // Re-initialize the Backend $this->initializeNewArchitecture(); } @@ -641,7 +651,8 @@ class Translator extends Preprocessor public function setTargetName(string $name): void { - // 如果指定了路径(包含目录分隔符),提取目录和文件名 + // If a path was given (contains a directory separator), split it into + // directory and file name. if (str_contains($name, '/') || str_contains($name, '\\')) { $this->outputDir = dirname($name); $name = basename($name); @@ -874,7 +885,7 @@ class Translator extends Preprocessor } $code .= "// class entry \n"; - // 确保数组大小至少为 1,避免 C/C++ 编译错误 + // Ensure the array has at least one element to avoid C/C++ compile errors. $code .= 'static THREAD_LOCAL zend_class_entry *' . self::PREFIX . self::CLASS_MAP . '[' . max(1, count($this->classMap)) . '];' . PHP_EOL; // Internal/compiled symbols have module lifetime. They are initialized // lazily after PHP startup, so disable_functions/disable_classes have @@ -888,7 +899,8 @@ class Translator extends Preprocessor $code .= $this->genPythonModuleStorage(); $code .= "// property \n"; - // 无动态 propMap:属性 offset 缓存仅覆盖编译类/内置类的声明属性(见 getPropertyId) + // No dynamic propMap: the property offset cache only covers declared + // properties of compiled/built-in classes (see getPropertyId). $code .= 'static php::PersistentCacheSlot ' . self::PREFIX . self::PERSISTENT_PROP_MAP . '[' . max(1, count($this->persistentPropMap)) . ']{};' . PHP_EOL; $code .= "// functions \n"; @@ -1331,8 +1343,10 @@ CODE; } /** - * 检查 phpx/src/misc/ 下的源文件是否已有有效缓存,始终生效(除非指定 --force)。 - * 缓存必须匹配编译命令和 PHP ABI,且 .o 文件必须不早于源文件和 phpx 头文件。 + * Check whether source files under phpx/src/misc/ have a valid cache, always + * effective (unless --force is specified). The cache must match the compile + * command and the PHP ABI, and the .o file must not be older than the source + * files and phpx headers. */ public function hasMiscObjectFileCache(string $cppFile): bool { @@ -1427,7 +1441,7 @@ CODE; } /** - * 判断文件是否为 C++ 源文件 + * Determine whether a file is a C++ source file. */ protected function isCppFile(string $filePath): bool { @@ -1436,10 +1450,10 @@ CODE; } /** - * 根据文件扩展名获取语言类型标识(用于 -x 参数). + * Get the language type identifier from the file extension (used for the -x flag). * - * @return string|null 语言标识(c, assembler, objective-c, objective-c++), - * 或 null 表示使用默认检测(C++ 文件) + * @return string|null Language identifier (c, assembler, objective-c, objective-c++), + * or null to use the default detection (C++ files). */ protected function getLanguageFromExtension(string $filePath): ?string { @@ -1455,7 +1469,7 @@ CODE; } /** - * 判断文件是否为原生编译型源文件(C/C++/汇编/ObjC 等). + * Determine whether a file is a natively compiled source file (C/C++/asm/ObjC, etc.). */ protected function isNativeSourceFile(string $filePath): bool { @@ -1521,7 +1535,7 @@ CODE; { $job = $this->maxJob; - // embed 需要 main 函数,以及 cli 的内置函数定义 + // The embed build needs the main function and the CLI's built-in function definitions. if ($this->isBuildModeEmbed()) { $runtimeSource = $this->getPhpxDir() . '/src/misc/typephp_runtime.cc'; // PHPX 2.6.3 keeps the common runtime in typephp_main.cc. Newer @@ -1540,14 +1554,14 @@ CODE; $this->preparePhpXPrecompiledHeader(); - // Windows 平台:编译资源文件(图标、版本信息等) + // Windows: compile the resource file (icon, version info, etc.) $this->compileResourceFile(); if (!$this->getPlatform()->supportsPcntlParallelCompile() or $job <= 1) { return $this->compileSourceFile($sourceFiles); } - // Unix/Linux/macOS 使用 pcntl 并行编译 + // Unix/Linux/macOS compile in parallel using pcntl return $this->compileWithPcntl($sourceFiles, $job); } @@ -1637,7 +1651,7 @@ CODE; } /** - * Unix/Linux/macOS 平台并行编译(使用 pcntl) + * Parallel compilation on Unix/Linux/macOS (using pcntl). */ protected function pcntlWait(?int &$status): int { @@ -1755,7 +1769,7 @@ CODE; { $targetFile = $this->getTargetFileName(); - // Windows 平台:将 .res 资源文件加入链接 + // Windows: add the .res resource file to the link if ($this->isWindows() && $this->hasResourceFile()) { $resFile = $this->getResourceResFile(); if (file_exists($resFile)) { @@ -2558,7 +2572,7 @@ CODE; $this->sanitize = (string) $sanitize; } - // 读取 cxx-flags + // Read cxx-flags $cxxFlags = $cfg['cxx-flags'] ?? null; if (!empty($cxxFlags)) { if (is_array($cxxFlags)) { @@ -2568,25 +2582,25 @@ CODE; } } - // 读取 cxx-std + // Read cxx-std $cxxStd = $cfg['cxx-std'] ?? null; if (!empty($cxxStd)) { $this->cxxStd = $cxxStd; } - // 读取 march(目标 CPU 指令集) + // Read march (target CPU instruction set) $march = $cfg['march'] ?? null; if (!empty($march)) { $this->march = $march; } - // 读取 target-platform + // Read target-platform $targetPlatform = $cfg['target-platform'] ?? null; if (!empty($targetPlatform)) { $this->targetPlatform = (string) $targetPlatform; } - // 读取 build-dir + // Read build-dir $buildDir = $cfg['build-dir'] ?? null; if (!empty($buildDir)) { $this->setBuildDir($this->resolvePath((string) $buildDir, $projectDir, 'Build path')); @@ -2596,7 +2610,7 @@ CODE; $this->dryRun = true; } - // 读取 ld-flags + // Read ld-flags $ldflags = $cfg['ld-flags'] ?? null; if (!empty($ldflags)) { if (is_array($ldflags)) { @@ -2606,7 +2620,7 @@ CODE; } } - // 读取 include-paths + // Read include-paths $includePaths = $cfg['include-paths'] ?? null; if (!empty($includePaths) && is_array($includePaths)) { foreach ($includePaths as $includePath) { @@ -2614,7 +2628,7 @@ CODE; } } - // 读取 defines + // Read defines $defines = $cfg['defines'] ?? null; if (!empty($defines) && is_array($defines)) { foreach ($defines as $define) { @@ -2622,17 +2636,17 @@ CODE; } } - // 读取 lto + // Read lto if (!empty($cfg['lto'])) { $this->enableLto = true; } - // 读取 format + // Read format if (!empty($cfg['format'])) { $this->enableCodeFormattingIfAvailable('YAML format'); } - // 读取 link-libs + // Read link-libs $linkLibs = $cfg['link-libs'] ?? null; if (!empty($linkLibs) && is_array($linkLibs)) { foreach ($linkLibs as $lib) { @@ -2640,7 +2654,7 @@ CODE; } } - // 读取 link-paths + // Read link-paths $linkPaths = $cfg['link-paths'] ?? null; if (!empty($linkPaths) && is_array($linkPaths)) { foreach ($linkPaths as $linkPath) { @@ -2675,7 +2689,8 @@ CODE; } } - // 读取 output/name。name 只表示目标名,不能按 YAML 目录解析成输出路径。 + // Read output/name. `name` only denotes the target name; it must not be + // resolved against the YAML directory as an output path. $output = $cfg['output'] ?? null; if (!empty($output)) { $this->setOutputPath($this->resolvePath((string) $output, $projectDir, 'Output path')); @@ -2683,19 +2698,19 @@ CODE; $this->setTargetName((string) $cfg['name']); } - // 读取 cpp-compiler + // Read cpp-compiler $cppCompiler = $cfg['cpp-compiler'] ?? null; if (!empty($cppCompiler)) { $this->setCppCompiler($cppCompiler); } - // 读取 mode/type/build-mode(支持 CLI/YAML 两套命名) + // Read mode/type/build-mode (supports both the CLI and YAML naming) $buildMode = $cfg['mode'] ?? $cfg['build-mode'] ?? $cfg['type'] ?? null; if (!empty($buildMode)) { $this->setBuildMode((string) $buildMode); } - // 读取 ignore(支持中横线和下划线) + // Read ignore (supports both hyphen and underscore) $ignore = $cfg['ignore'] ?? null; if (!empty($ignore)) { if (!is_array($ignore)) { @@ -2713,13 +2728,13 @@ CODE; } } - // 读取 resource(Windows 资源配置:图标、版本信息) + // Read resource (Windows resource config: icon, version info) $resource = $cfg['resource'] ?? null; if (!empty($resource)) { if (!is_array($resource)) { $this->error('`resource` must be array'); } - // 验证图标文件是否存在 + // Verify that the icon file exists if (!empty($resource['icon'])) { $iconPath = $resource['icon']; if (!preg_match('/^[A-Za-z]:\\|^\//', $iconPath)) { @@ -2733,7 +2748,7 @@ CODE; $this->resourceConfig['_projectDir'] = $projectDir; } - // 读取 manifest(Windows 清单文件,与 resource 同级,缺省不携带) + // Read manifest (Windows manifest file, same level as resource, omitted by default) $manifest = $cfg['manifest'] ?? null; if (!empty($manifest)) { if (!is_string($manifest)) { @@ -2893,7 +2908,7 @@ CODE; foreach ($interfaceDef->extendsList ?: ($interfaceDef->extends ? [$interfaceDef->extends] : []) as $parent) { $tmpCe = self::PREFIX . 'class_entry_' . $this->escapeCeName($parent); - // 不存在的接口,说明可能是内置接口 + // A non-existent interface is likely a built-in interface if (!$this->hasInterface($parent)) { $sorter->add($tmpCe); } @@ -2917,7 +2932,7 @@ CODE; $deps = []; $parent = $classDef->extends; if ($parent) { - // 不存在的父类,说明可能是内置类 + // A non-existent parent is likely a built-in class $tmpCe = $this->getParentClassCe($classDef); if (!$this->hasClass($parent)) { $sorter->add($tmpCe); @@ -3567,8 +3582,9 @@ CODE; ); } - // 如果不是继承自内置类,需要检查父类是否存在,在预处理阶段只需检查了是否继承内置类 - // 目前不允许继承自动态加载的自定义类 + // When not inheriting from a built-in class, verify the parent exists. + // The preprocess phase only checks whether a built-in class is inherited. + // Currently, inheriting from an autoloaded custom class is not allowed. if ($this->classDef->extends and !$this->classDef->inheritedFromInternalClass) { $parentClass = $this->getNamespacedClassName($this->parseIdentifier($class->extends)); if ($this->hasClass($parentClass)) { @@ -3579,7 +3595,7 @@ CODE; 'Native and ZendVM-backed classes cannot inherit from each other' ); } - // 父类是 final 无法继承 + // The parent class is final and cannot be extended if ($parent->flags & Modifiers::FINAL) { $this->fatalError($class, "Class `{$this->class}` cannot extend final class `{$parentClass}`"); } @@ -3787,7 +3803,9 @@ CODE; $isEntryFunction = $this->hasFunction(self::ENTRY_FUNCTION) && $functionDef === $this->getFunction(self::ENTRY_FUNCTION); if ($this->isBuildModeBin() && $isEntryFunction) { - // $_SERVER 的初始化必须置于 main 入口函数内,以确保在其被访问前,运行环境及超全局上下文已完全就绪。 + // $_SERVER initialization must live inside the main entry function so + // the runtime environment and superglobal context are fully ready + // before it is accessed. $cppCode .= $this->registerServerEnvironment($functionDef->sourceFile); } $callParams = $functionDef->argInfoList ? rtrim($callParams, ',') : ''; @@ -3817,8 +3835,10 @@ CODE; private function registerServerEnvironment(string $entryFile): string { /** - * 对于常驻内存型应用,执行完当前逻辑后,会立即进入长时间的事件循环等待。 - * 因此,这些变量仅作为临时用途,用完后应即刻销毁,无需长期持有。 + * For long-running (resident) applications, control enters a long-lived + * event loop immediately after the current logic finishes. These + * variables are therefore only temporary and should be destroyed as soon + * as they are used, rather than held for the long term. */ $indent = $this->getIndent(); $cppCode = $indent . "const char *value = " . $this->genCharPtr($entryFile, true) . ';' . PHP_EOL; @@ -3870,7 +3890,7 @@ CODE; { $cppCode = ''; - // 接口没有方法实体 + // Interfaces have no method bodies if ($classDef instanceof ClassDef && $classDef->trait === null) { if ($classDef->nativeObject) { return ''; @@ -3927,14 +3947,15 @@ CODE; } $this->functionDef = $this->getFunction($name); - // 类方法不要保存到 functions 中 + // Class methods are not stored in `functions` if ($this->methodDef) { $this->methodDef->functionDef = $this->functionDef; } else { $this->functionDefineInFile[$name] = $this->functionDef; } - // stub 函数,没有函数的具体实现,只有声明,实现在 C++ 或者 .so 中定义 + // Stub functions have no concrete implementation, only a declaration; + // the implementation is defined in C++ or a .so file. if ($this->functionDef->stub) { $this->resetFunction(); return ''; @@ -4062,7 +4083,7 @@ CODE; $code .= $preamble . PHP_EOL; } $this->indentLevel--; - // 构建 PHP 级别的函数名用于 debug backtrace + // Build the PHP-level function name for debug backtraces if ($this->class) { $debugName = $this->class . '::' . $this->function; } else { @@ -4103,7 +4124,8 @@ CODE; } /** - * 检查父类方法是否可以被重写,私有方法不能被重写,方法签名必须兼容 + * Check whether a parent method can be overridden: private methods cannot be + * overridden, and the signature must be compatible. */ protected function checkParentMethodCanBeOverridden(Node\Stmt\ClassMethod $v, string $name): void { @@ -4118,7 +4140,7 @@ CODE; if (!$extends) { break; } - // 父类是内置类 + // The parent class is a built-in class if ($classDef->inheritedFromInternalClass) { $modifiers = Reflection::getClassMethodModifiers($extends, $name); if ($modifiers & \ReflectionMethod::IS_PRIVATE) { @@ -5066,7 +5088,8 @@ CODE; && !$this->hasMatchingOverrideDeclaration($this->classDef, $name)) { $this->fatalMissingOverride($v, $this->classDef->getNamespacedName(false), $name); } - // 预处理阶段没有父类的信息,只能在实现阶段检查 + // The preprocess phase has no parent-class info, so the check can + // only run in the implementation phase. $this->checkParentMethodCanBeOverridden($v, $name); $methodCodes[$name] = $this->parseFunction($v); } diff --git a/src/TypeSystem/NativeTypeCompatibilityTrait.php b/src/TypeSystem/NativeTypeCompatibilityTrait.php index e223fef9..bc25bcc9 100644 --- a/src/TypeSystem/NativeTypeCompatibilityTrait.php +++ b/src/TypeSystem/NativeTypeCompatibilityTrait.php @@ -30,10 +30,14 @@ trait NativeTypeCompatibilityTrait protected function isInheritedFrom(string $class, string $expected): bool { - // 继承关系判断的唯一入口。调用者不应直接使用 PHP 运行时反射函数判断普通项目类。 - // 对 AOT 已扫描到的项目类/接口,必须走 classDef/interfaceDef 中的 extends/implements 图; - // 对 PHP 内置类/接口,可以使用 Zend 运行时反射,因为这部分属于目标 PHP 运行时的固定能力; - // 对动态类返回 true 表示“静态阶段无法否定”,后续必须保留运行时检查兜底。 + // The single entry point for inheritance checks. Callers must not use PHP + // runtime reflection functions directly to judge ordinary project classes. + // For project classes/interfaces already scanned by AOT, the extends/ + // implements graph in classDef/interfaceDef must be followed; for PHP + // built-in classes/interfaces, Zend runtime reflection may be used, since + // these are fixed capabilities of the target PHP runtime. Returning true + // for a dynamic class means "cannot be disproven at static time", so a + // runtime check must be retained as a fallback. $class = ltrim($class, '\\'); $expected = ltrim($expected, '\\'); if (strcasecmp($class, $expected) === 0) { @@ -51,15 +55,18 @@ trait NativeTypeCompatibilityTrait } if ($this->isInternalClass($class) or $this->isInternalInterface($class)) { - // 只允许内置类型之间使用 Zend 的继承关系。这里不是查询任意用户类, - // 因此不会把编译器进程加载过的外部库类混入项目静态类型系统。 + // Zend's inheritance relation is only used between built-in types. + // This is not a query on an arbitrary user class, so external library + // classes loaded by the compiler process are never mixed into the + // project's static type system. if (!$internal) { return false; } return is_subclass_of($class, $expected); } - // 类不存在,说明这是一个动态类,跳过静态检查,需要运行时检查 + // If the class does not exist, it is a dynamic class; skip the static + // check and defer to a runtime check if (!$this->hasClass($class)) { return true; } @@ -103,8 +110,9 @@ trait NativeTypeCompatibilityTrait return true; } if (!$this->hasClass($class)) { - // 原生类继承自一个内置类,例如: UserError extends Exception ,然后 $expected 预期是 Throwable - // 这种情况,需要使用 ZendVM 获取继承关系 + // A native class extends a built-in class (e.g. UserError extends + // Exception), and $expected is Throwable. In this case ZendVM must + // be used to obtain the inheritance relation. if ($this->isInternalClass($class) and $internal) { return $class === $expected or is_subclass_of($class, $expected); } @@ -116,8 +124,11 @@ trait NativeTypeCompatibilityTrait } $class = $classDef->extends; if ($this->isInternalClass($class)) { - // 项目类可以继承内置类。进入内置父类链后,后续关系交给 Zend 判断; - // 但 expected 也必须是内置类/接口,否则不能跨到外部用户类命名空间做运行时反射。 + // Project classes may extend built-in classes. Once the built-in + // parent chain is entered, further relations are delegated to Zend; + // however, $expected must also be a built-in class/interface, + // otherwise runtime reflection cannot cross into the external user + // class namespace. return $internal && is_subclass_of($class, $expected); } $classDef = $this->getClass($class); @@ -126,8 +137,10 @@ trait NativeTypeCompatibilityTrait private function interfaceExtends(string $interface, string $expected): bool { - // 接口继承需要单独处理,因为 interfaceDef 没有 classDef 的父类链。 - // 这里同样只遍历 AOT 已知接口图;遇到内置接口时,才允许使用 Zend 的 is_subclass_of()。 + // Interface inheritance is handled separately because interfaceDef has no + // parent chain like classDef. Only the AOT-known interface graph is + // traversed here; Zend's is_subclass_of() is allowed only when a built-in + // interface is encountered. $stack = [$interface]; while ($stack) { $check = array_pop($stack); @@ -228,7 +241,8 @@ trait NativeTypeCompatibilityTrait } if ($this->isVarExpr($arg->value)) { $var = $this->parseVariable($arg->value); - // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 + // For a by-reference parameter, an undefined variable may be passed; + // it is created immediately as a reference if (!$this->hasLocalVar($var)) { $this->addLocalVar($var, Type::VAR); } @@ -266,10 +280,13 @@ trait NativeTypeCompatibilityTrait if ($declaredClass !== '') { $class = $this->detectDeclaredClassOfExpr($arg->value); if ($class !== '') { - // native call 是性能热点,若静态阶段已经证明实参 is-a 声明类型, - // 就不要再生成 php::toObject($expr, target_ce) 做重复运行时检查。 - // 如果无法证明,但右值是已知 concrete object,说明一定不兼容,直接编译期 fatal; - // 其他动态/外部库/any 场景保留 php::toObject() 作为运行时兜底。 + // Native calls are a performance hot path. If the static phase + // has already proven the argument is-a the declared type, do not + // emit php::toObject($expr, target_ce) to repeat the runtime + // check. If it cannot be proven but the right-hand side is a + // known concrete object, it is necessarily incompatible, so fail + // at compile time; other dynamic/external-library/any scenarios + // keep php::toObject() as a runtime fallback. if ($this->isObjectClassStaticallyAssignableTo($class, $declaredClass)) { return $type === Type::OBJECT ? $expr : $this->convertObjectExpr($expr); } diff --git a/src/compiler.php b/src/compiler.php index d8f66778..c03e2fce 100644 --- a/src/compiler.php +++ b/src/compiler.php @@ -47,7 +47,7 @@ function main(int $argc, array $argv): void return; } - // .prof 文件分析模式:./tpc app.prof + // .prof file analysis mode: ./tpc app.prof if ($argc >= 2 && str_ends_with($argv[1], '.prof')) { profileAnalyze($argc, $argv); return; @@ -57,9 +57,9 @@ function main(int $argc, array $argv): void $translator = new Translator(TYPEPHP_ROOT_PATH); $translator->setIndent(' '); - // 扫描所有 PHP 文件,预处理 + // Scan all PHP files and preprocess them. $files = $translator->prepare($translator->parseArgv($argv)); - // 生成 C++ 文件 + // Generate the C++ source files. $sourceFiles = $translator->convert($files); $wasmManifest = getenv('TYPEPHP_WASM_INTERFACE_MANIFEST'); @@ -87,7 +87,7 @@ function main(int $argc, array $argv): void $sourceFiles[] = $wasmAdapter; } - // --dry 模式:仅生成 C++ 代码,不执行编译 + // --dry mode: only generate the C++ code, without compiling. if ($translator->isDryRun()) { $buildDir = $translator->getBuildDir(); $count = count($sourceFiles); @@ -105,11 +105,11 @@ function main(int $argc, array $argv): void return; } - // 编译所有 C++ 文件 + // Compile all C++ source files. $objectFiles = $translator->compile($sourceFiles); - // 连接所有目标文件,生成可执行文件 + // Link all object files to produce the executable. $binaryFile = $translator->build($objectFiles); - // 如果指定了 --run / -r,编译完成后立即执行 + // If --run / -r was specified, execute immediately after compilation. if ($translator->isRunRequested()) { $translator->run($binaryFile); // never returns } @@ -310,7 +310,7 @@ function profileAnalyze(int $argc, array $argv): void exit(1); } - // 从 prof 文件名推导二进制文件名(app.prof → app) + // Derive the binary name from the prof file name (app.prof → app). $binary = basename($profFile, '.prof'); if (!file_exists($binary) && file_exists('./' . $binary)) { $binary = './' . $binary; diff --git a/src/gen_stub.php b/src/gen_stub.php index d559806c..85547588 100755 --- a/src/gen_stub.php +++ b/src/gen_stub.php @@ -2494,7 +2494,8 @@ OUPUT_EXAMPLE return null; } foreach ($generatedFuncInfos as $generatedFuncInfo) { - // TODO 从数组遍历元素,调用方法,在编译期无法获得元素的类型,因此判断作用域,必须为 public 方法 + // TODO When iterating elements from an array and calling a method, the element type cannot be + // determined at compile time, so check the scope and require the method to be public. if ($generatedFuncInfo->equalsApartFromNameAndRefcount($this)) { return $generatedFuncInfo; } @@ -2695,7 +2696,8 @@ class EvaluatedValue $constType = ($const->phpDocType ?? $const->type)->tryToSimpleType(); if ($constType) { - // 这里返回的并不是真正的值,而是一个类型的占位符,最终的运算由编译器完成,此处仅用于 ArgInfo 处理 + // What is returned here is not the real value but a type placeholder; the final computation + // is performed by the compiler. This is only used for ArgInfo processing. if ($constType->isBool()) { return true; } elseif ($constType->isInt()) { @@ -3488,7 +3490,7 @@ class StringBuilder { $versions = [ PHP_85_VERSION_ID => self::PHP_85_KNOWN, PHP_84_VERSION_ID => self::PHP_84_KNOWN, - PHP_82_VERSION_ID => self::PHP_82_KNOWN, // 8.3 合并到 8.2 + PHP_82_VERSION_ID => self::PHP_82_KNOWN, // 8.3 is merged into 8.2 PHP_81_VERSION_ID => self::PHP_81_KNOWN, ]; @@ -3619,7 +3621,7 @@ class PropertyInfo extends VariableLike ); if (!$useEmptyArrayDefault) { - // New 操作作为属性的默认值,需编译器处理 gen_stub 作为 null 值 + // A New expression as a property default requires compiler handling; gen_stub treats it as a null value. if ($this->defaultValue === null || $this->defaultValue instanceof Expr\New_) { $defaultValue = EvaluatedValue::null(); } else { @@ -5041,7 +5043,7 @@ class FileInfo { $this->getMinimumPhpVersionIdCompatibility(), $this->isUndocumentable ); - // 清理当前类名,避免污染 + // Clear the current class name to avoid leaking it into subsequent classes. ClassInfo::$currentClass = ''; continue; } @@ -5253,7 +5255,7 @@ class FramelessFunctionInfo { } /** - * 获取魔术方法的默认返回值类型。只有用户未显式声明类型时才使用。 + * Get the default return type of a magic method. Used only when the user has not explicitly declared a type. */ function getMagicMethodDefaultReturnType(FunctionOrMethodName $name): ?string { @@ -5277,7 +5279,7 @@ function getMagicMethodDefaultReturnType(FunctionOrMethodName $name): ?string } /** - * 获取魔术方法的默认参数类型。只有用户未显式声明类型时才使用。 + * Get the default parameter type of a magic method. Used only when the user has not explicitly declared a type. */ function getMagicMethodDefaultParamType(FunctionOrMethodName $name, int $index): ?string { @@ -5934,7 +5936,7 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co $underscoreName = implode("_", $className->getParts()); $functionEntryName = "class_{$underscoreName}_methods"; } else { - // 跳过生成 ext_functions + // Skip generating ext_functions. $functionEntryName = "ext_functions"; return ''; }