From 43cb0948e1bbe8c266f2b0bd0d1927969ff433b9 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 26 Feb 2026 21:05:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor(php):=20=E4=BC=98=E5=8C=96PHP=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=99=A8=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5=E5=92=8C?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加ClassConstFetch类型的检测方法 - 增加对VariadicPlaceholder的错误处理 - 移除静态属性获取的特殊处理逻辑 - 优化表达式解析的通用处理流程 - 修复最后行返回语句检测的边界情况 - 使用常量替换硬编码类型字符串 - 统一魔法方法参数类型验证方式 --- src/Php/AstNodeType.php | 5 +++++ src/Php/CompilerBase.php | 16 ++++++++++------ src/Php/MagicMethodDetector.php | 14 +++++++------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Php/AstNodeType.php b/src/Php/AstNodeType.php index aee2488e..a8801385 100644 --- a/src/Php/AstNodeType.php +++ b/src/Php/AstNodeType.php @@ -39,6 +39,11 @@ trait AstNodeType return $expr instanceof Expr\StaticPropertyFetch; } + protected function isClassConstFetch(NodeAbstract $expr): bool + { + return $expr instanceof Expr\ClassConstFetch; + } + protected function isNewExpr(NodeAbstract $expr): bool { return $expr instanceof Expr\New_; diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 881731af..ffcd6be9 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -2066,6 +2066,9 @@ class CompilerBase extends \PhpAot\Core\Translator $list_args = []; $last = array_key_last($args); foreach ($args as $i => $arg) { + if ($arg instanceof Node\VariadicPlaceholder) { + $this->fatalError($arg, 'Variadic place holder are not supported'); + } if ($arg->name !== null) { $this->fatalError($arg, 'Named arguments are not supported'); } @@ -3127,16 +3130,14 @@ class CompilerBase extends \PhpAot\Core\Translator } elseif ($this->isPropertyFetch($expr)) { $name = $this->identifierToStr($expr->name); $list[] = '{php::PropertyFetch, ' . self::TYPE_VAR . '(' . $name . ')}'; - } elseif ($this->isStaticPropertyFetch($expr)) { - $var = $this->genTmpVarName(); - $this->addLocalVar($var, self::TYPE_VAR); - $this->beforeStmtLines[] = $var . '=' . $this->parseStaticPropertyFetch($expr) . ';'; - break; } elseif ($this->isVarExpr($expr)) { $var = $this->parseIdentifier($expr); break; } else { - $this->fatalError($expr, 'The ' . $op . '() only supports variables, array fetch, and property read'); + $var = $this->genTmpVarName(); + $this->addLocalVar($var, self::TYPE_VAR); + $this->beforeStmtLines[] = $var . '=' . $this->parseExpr($expr) . ';'; + break; } $expr = $expr->var; } @@ -3987,6 +3988,9 @@ class CompilerBase extends \PhpAot\Core\Translator protected function isReturnStmtInLastLine(array $stmts): bool { + if (count($stmts) === 0) { + return false; + } return $stmts[array_key_last($stmts)] instanceof Node\Stmt\Return_; } } diff --git a/src/Php/MagicMethodDetector.php b/src/Php/MagicMethodDetector.php index 88d3d322..46c95754 100644 --- a/src/Php/MagicMethodDetector.php +++ b/src/Php/MagicMethodDetector.php @@ -19,7 +19,7 @@ trait MagicMethodDetector if (count($methodDef->functionDef->argInfoList) != 2) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 2 arguments"); } - if (!$methodDef->functionDef->argInfoList[0]->type or $methodDef->functionDef->argInfoList[0]->type != 'string') { + if ($methodDef->functionDef->argInfoList[0]->type and $methodDef->functionDef->argInfoList[0]->type != self::TYPE_STR) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take string as argument"); } } elseif ($name == '__get') { @@ -27,33 +27,33 @@ trait MagicMethodDetector $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); } } elseif ($name == '__toString') { - if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != 'string') { + if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != self::TYPE_STR) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return string"); } } elseif ($name == '__serialize') { - if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != 'array') { + if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != self::TYPE_ARRAY) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array"); } } elseif ($name == '__unserialize') { if (count($methodDef->functionDef->argInfoList) != 1) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); - } elseif (!$methodDef->functionDef->argInfoList[0]->type or $methodDef->functionDef->argInfoList[0]->type != 'array') { + } elseif (!$methodDef->functionDef->argInfoList[0]->type or $methodDef->functionDef->argInfoList[0]->type != self::TYPE_ARRAY) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take array as argument"); } } elseif ($name == '__isset' or $name == '__unset' or $name == '__set_state') { if (count($methodDef->functionDef->argInfoList) != 1) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); } - if (!$methodDef->functionDef->argInfoList[0]->type or $methodDef->functionDef->argInfoList[0]->type != 'string') { + if (!$methodDef->functionDef->argInfoList[0]->type or $methodDef->functionDef->argInfoList[0]->type != self::TYPE_STR) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take string as argument"); } if ($name == '__set_state') { - if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != 'array') { + if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != self::TYPE_ARRAY) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array"); } } } elseif ($name == '__debugInfo') { - if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != 'array') { + if (!$methodDef->functionDef->returnType or $methodDef->functionDef->returnType != self::TYPE_ARRAY) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array"); } }