diff --git a/phpunit/code/compiler_api/const_decl.php b/phpunit/code/compiler_api/const_decl.php new file mode 100644 index 00000000..a80363be --- /dev/null +++ b/phpunit/code/compiler_api/const_decl.php @@ -0,0 +1,3 @@ +assertSame('ZEND_LONG_MIN', $this->compiler->getConstValue('PHP_INT_MIN')); } + public function testConstDeclarationsAreStaticallyExpanded(): void + { + $this->compiler->prepareFile($this->fixturePath('const_decl.php')); + + $code = $this->invokeMethod( + 'parseConstFetch', + new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('AOT_COMPILE_TIME_CONST')) + ); + + $this->assertSame(CompilerBase::CONST_VAR . 'AOT_COMPILE_TIME_CONST', $code); + } + + public function testDefineConstantsAreNotStaticallyExpanded(): void + { + $internalConstants = $this->getPropertyValue('internalConstants'); + $this->assertArrayHasKey('PHP_VERSION', $internalConstants); + $this->assertArrayNotHasKey('ROOT_PATH', $internalConstants); + + $code = $this->invokeMethod( + 'parseConstFetch', + new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('ROOT_PATH')) + ); + + $this->assertStringStartsWith('php::constant(nullptr, ', $code); + $this->assertStringNotContainsString(ROOT_PATH, $code); + } + + public function testDynamicallyDefinedConstantsAreNotInternalConstants(): void + { + $name = 'AOT_USER_DEFINE_' . str_replace('.', '_', uniqid('', true)); + define($name, 'runtime-value'); + + $compiler = CompilerTest::create($this->testDir); + $ref = new \ReflectionClass($compiler); + $prop = $ref->getProperty('internalConstants'); + $prop->setAccessible(true); + + $this->assertArrayNotHasKey($name, $prop->getValue($compiler)); + } + // ======================================================================== // genAnonClassName // ======================================================================== diff --git a/src/Php/Translator.php b/src/Php/Translator.php index f617ea7f..973a2d59 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -128,7 +128,7 @@ class Translator extends Preprocessor // 这样可以确保优先级:命令行 > YAML > 默认值 $this->internalFunctions = array_flip(get_defined_functions()['internal']); unset($this->internalFunctions[self::ENTRY_FUNCTION]); - $this->internalConstants = get_defined_constants(); + $this->internalConstants = $this->loadInternalConstants(); if ($this->climate->arguments->defined('help')) { $this->showUsage(); exit(0); @@ -148,6 +148,26 @@ class Translator extends Preprocessor $this->detectPlatform(); } + protected function loadInternalConstants(): array + { + $groups = get_defined_constants(true); + if (!is_array($groups)) { + return get_defined_constants(); + } + + $constants = []; + foreach ($groups as $groupName => $group) { + // 编译器进程中的用户常量属于被编译程序的运行时状态,不能在静态阶段展开。 + if (strcasecmp((string) $groupName, 'user') === 0 || !is_array($group)) { + continue; + } + foreach ($group as $name => $value) { + $constants[$name] = $value; + } + } + return $constants; + } + /** * 检测操作系统、编译器以及 Windows 平台的 PHP lib 文件 */