From 0e44edd42c8eb8bc9267bd8001e4956046000016 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 26 Feb 2026 18:24:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E6=B7=BB=E5=8A=A0=E9=9D=99?= =?UTF-8?q?=E6=80=81=E5=8F=98=E9=87=8F=E6=94=AF=E6=8C=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 STATIC_VAR 常量用于标识静态变量前缀 - 添加 staticVars 属性用于跟踪静态变量状态 - 在 resetFunction 中重置静态变量数组 - 实现 getStaticVarName 方法生成静态变量名称 - 修改 parseVariable 处理静态变量解析逻辑 - 添加 addStaticVar 和 hasStaticVar 辅助方法 - 更新 hasVar 检查静态变量存在性 - 实现静态变量初始化代码生成逻辑 - 添加静态变量测试用例验证功能正确性 --- src/Php/CompilerBase.php | 75 +++++++++++++++++++++++++++++++------- tests/aot/static-vars.phpt | 41 +++++++++++++++++++++ 2 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 tests/aot/static-vars.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 2beea009..23dd7d58 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -63,6 +63,7 @@ class CompilerBase extends \PhpAot\Core\Translator public const string PREFIX = 'php_'; public const string ANON_CLASS = '_anon_class_'; + public const string STATIC_VAR = '_static_var_'; public const string OP_ISSET = 'isset'; public const string OP_EMPTY = 'empty'; public const string OP_NOP = "if (0) {}\n"; @@ -186,6 +187,7 @@ class CompilerBase extends \PhpAot\Core\Translator */ protected array $objects = []; protected array $localVars = []; + protected array $staticVars = []; protected array $objectWrappers = []; protected bool $strictTypes = false; protected string $rootPath; @@ -556,6 +558,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function resetFunction(): void { $this->localVars = []; + $this->staticVars = []; $this->arguments = []; $this->objectWrappers = []; $this->tmpVarIndex = 0; @@ -599,6 +602,25 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->getNativeName($this->parseIdentifier($v->name), $this->namespace, $this->class); } + protected function getStaticVarName(string $name): string + { + $prefix = self::STATIC_VAR; + if ($this->namespace) { + $prefix .= $this->namespace . '_'; + } + if ($this->class) { + $prefix .= $this->class . '_'; + if ($this->method) { + $prefix .= $this->method . '_'; + } + } else { + if ($this->function) { + $prefix .= $this->function . '_'; + } + } + return $prefix . $name; + } + protected function getNamespacedClassName(string $class): string { if ($class[0] === '\\') { @@ -843,18 +865,26 @@ class CompilerBase extends \PhpAot\Core\Translator } } + protected function parseVariable(Variable $expr): string + { + if (is_object($expr->name) and $this->isVarExpr($expr->name)) { + $this->fatalError($expr, 'The `$$` syntax is not supported'); + } + if ($this->isSuperGlobal($expr->name) and !$this->hasGlobalVar($expr->name)) { + $this->addGlobalVar($expr->name, $this->superGlobalVars[$expr->name]); + } + if ($this->hasStaticVar($expr->name)) { + return $this->getStaticVarName($expr->name); + } + return $this->escapeVarName($expr->name); + } + protected function parseIdentifier(NodeAbstract $expr): string { $type = $expr->getType(); switch ($type) { case self::EXPR_VARIABLE: - if (is_object($expr->name) and $this->isVarExpr($expr->name)) { - $this->fatalError($expr, 'The `$$` syntax is not supported'); - } - if ($this->isSuperGlobal($expr->name) and !$this->hasGlobalVar($expr->name)) { - $this->addGlobalVar($expr->name, $this->superGlobalVars[$expr->name]); - } - return $this->escapeVarName($expr->name); + return $this->parseVariable($expr); case 'Name': case 'VarLikeIdentifier': case 'Identifier': @@ -1350,6 +1380,12 @@ class CompilerBase extends \PhpAot\Core\Translator $this->localVars[$name] = $type; } + protected function addStaticVar(string $name, string $type): void + { + $this->staticVars[$name] = $type; + $this->addGlobalVar($this->getStaticVarName($name), $type); + } + protected function addArgument(string $name, string $type): void { $this->arguments[$name] = $type; @@ -1376,7 +1412,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function hasVar(string $name): bool { - return $this->hasLocalVar($name) || $this->hasGlobalVar($name); + return $this->hasLocalVar($name) || $this->hasGlobalVar($name) || $this->hasStaticVar($name); } protected function hasLocalVar(string $name): bool @@ -2939,11 +2975,19 @@ class CompilerBase extends \PhpAot\Core\Translator { $list = []; foreach ($v->vars as $var) { + $varName = $var->var->name; + $type = $var->default ? $this->detectExprType($var->default) : self::TYPE_VAR; + $this->addStaticVar($varName, $type); if ($var->default) { - $type = $this->detectExprType($var->default); - $list[] = 'static ' . $type . ' ' . $this->parseIdentifier($var->var) . ' = ' . $this->parseIdentifier($var->default) . ';'; - } else { - $list[] = 'static ' . self::TYPE_VAR . ' ' . $this->parseIdentifier($var->var) . ';'; + $initState = self::STATIC_VAR . $varName . '_initialized'; + $initCode = $this->getIndent() . 'static bool ' . $initState . ' = false;'; + $initCode .= $this->getIndent() . "if (!$initState) { \n"; + $this->indentLevel++; + $initCode .= $this->getIndent() . "$initState = true;\n"; + $initCode .= $this->getIndent() . $this->getStaticVarName($varName) . ' = ' . $this->parseIdentifier($var->default) . ';'; + $this->indentLevel--; + $initCode .= $this->getIndent() . '}'; + $list[] = $initCode; } } @@ -3095,11 +3139,16 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->convertArrayExpr($this->parseIdentifier($expr->expr)); } - protected function hasGlobalVar($name): bool + protected function hasGlobalVar(string $name): bool { return array_key_exists($name, $this->globalVars); } + protected function hasStaticVar(string $name): bool + { + return array_key_exists($name, $this->staticVars); + } + protected function parseCastDouble(mixed $expr): string { return $this->convertFloatExpr($this->parseIdentifier($expr->expr)); diff --git a/tests/aot/static-vars.phpt b/tests/aot/static-vars.phpt new file mode 100644 index 00000000..9ac9b8d1 --- /dev/null +++ b/tests/aot/static-vars.phpt @@ -0,0 +1,41 @@ +--TEST-- +static vars +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + int(100) +} +array(2) { + [0]=> + int(100) + [1]=> + int(100) +} +init var +int(999)