refactor(php): 优化PHP编译器类型检查和表达式处理

- 添加ClassConstFetch类型的检测方法
- 增加对VariadicPlaceholder的错误处理
- 移除静态属性获取的特殊处理逻辑
- 优化表达式解析的通用处理流程
- 修复最后行返回语句检测的边界情况
- 使用常量替换硬编码类型字符串
- 统一魔法方法参数类型验证方式
pull/1/head
韩天峰 6 months ago
parent 31a3275ecf
commit 43cb0948e1
  1. 5
      src/Php/AstNodeType.php
  2. 16
      src/Php/CompilerBase.php
  3. 14
      src/Php/MagicMethodDetector.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_;

@ -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_;
}
}

@ -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");
}
}

Loading…
Cancel
Save