refactor(php): 优化PHP编译器类型检查和函数定义逻辑

- 添加对内置类型的映射支持,改进类型解析逻辑
- 为函数定义添加精确返回类型标记功能
- 修复对象重新赋值时的类型检查条件判断
- 改进变量赋值时的类型验证规则,支持var类型灵活赋值
- 添加数组转换表达式类型识别支持
- 优化函数调用返回值类型获取逻辑
- 新增类继承关系检查辅助方法
- 改进参数传递时的对象类型验证
- 调整预处理器中的use语句解析顺序
- 修正符号调用记录中的类名解析逻辑
pull/1/head
韩天峰 5 months ago
parent 156fb0a8bf
commit 128b6b8a73
  1. 41
      src/Php/CompilerBase.php
  2. 2
      src/Php/Entity/FunctionDef.php
  3. 8
      src/Php/Preprocessor.php

@ -777,8 +777,10 @@ class CompilerBase extends \PhpAot\Core\Translator
// 属性和类常量的类型不能声明为 void/never ,只有返回值可以
if ($what !== self::DECL_TYPE_OF_RETURN and ($typeName === 'void' or $typeName === 'never')) {
$this->fatalError($type, 'The type `void`/`never` is allowed only for return type');
} else {
} elseif (isset($this->zendTypeMap[$typeName])) {
return $this->getTypeFromZendType($typeName);
} else {
return self::TYPE_OBJECT;
}
}
}
@ -801,6 +803,11 @@ class CompilerBase extends \PhpAot\Core\Translator
$fnName = $this->parseIdentifier($v->name);
$returnType = $this->parseTypeDecl($v->returnType, self::DECL_TYPE_OF_RETURN);
$functionDef = new FunctionDef($fnName, $returnType, $this->namespace, $this->stubFile);
// 函数返回值精确类型
if ($v->returnType != null and !($v->returnType instanceof UnionType or $v->returnType instanceof NullableType)) {
$functionDef->exactReturnType = true;
$functionDef->returnClass = $v->returnType;
}
$this->functionDef = $functionDef;
$this->parseParams($v->params, $functionDef);
@ -1374,7 +1381,9 @@ class CompilerBase extends \PhpAot\Core\Translator
$fullClass = $this->getNamespacedClassName($class);
if ($this->isTypedObject($var)) {
$leftClass = $this->getObjectType($var);
$this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$fullClass}`");
if ($leftClass !== $fullClass) {
$this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$fullClass}`");
}
}
$this->addObject($var, $fullClass);
$type = self::TYPE_OBJECT;
@ -1428,9 +1437,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->hasVar($var)) {
$this->addLocalVar($var, $type);
} else {
} elseif ($this->getVarType($var) !== self::TYPE_VAR) { // var 可以作为任意类型进行赋值
if ($this->isTypedObject($var) and $type !== self::TYPE_OBJECT
or $this->getVarType($var) === self::TYPE_ARRAY and ($type !== self::TYPE_ARRAY && $type !== self::TYPE_VAR)
or $this->getVarType($var) === self::TYPE_ARRAY and ($type !== self::TYPE_ARRAY)
) {
$this->fatalError($left, "Cannot re-assign variable `\${$var}` from " . $this->getVarType($var) . ' to ' . $type);
}
@ -1849,6 +1858,7 @@ class CompilerBase extends \PhpAot\Core\Translator
case 'Scalar_Bool':
return $this->getNativeType(self::TYPE_BOOL);
case 'Expr_Array':
case 'Expr_Cast_Array':
return self::TYPE_ARRAY;
case 'Expr_BinaryOp_Plus':
case 'Expr_BinaryOp_Minus':
@ -1895,8 +1905,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$nativeFunc = $this->findNativeMethod($expr, $object, $method);
if ($nativeFunc) {
$funcDef = $this->functions[$nativeFunc];
// 此函数尚未完成解析,仅经过初步的预处理,无法获得准确的返回值类型
if ($funcDef->completed) {
// 用户未定义类型,但函数已编译完成,通过分析代码获得了返回值类型
if ($funcDef->completed or $funcDef->exactReturnType) {
return $funcDef->returnType;
}
} elseif ($this->isTypedObject($object)) {
@ -3260,6 +3270,23 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->functionDef->returnType;
}
protected function isInheritedFrom(string $class, string $expected): bool
{
while (true) {
if (strcasecmp($class, $expected) === 0) {
return true;
}
if (!$this->hasClass($class)) {
return false;
}
$classDef = $this->getClass($class);
if (!$classDef->extends) {
return false;
}
$class = $classDef->extends;
}
}
protected function getTypeConvertedArg(Node\Arg $arg, ArgInfo $argInfo): string
{
$expr = $this->parseArg($arg);
@ -3274,7 +3301,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$object = $this->parseVariable($arg->value);
if ($this->isTypedObject($object)) {
$class = $this->getObjectType($object);
if ($argInfo->class and $class != $argInfo->class) {
if (!$this->isInheritedFrom($class, $argInfo->class)) {
$this->fatalError($arg, "Argument `{$argInfo->name}` must be an instance of `{$argInfo->class}`, `{$class}` given");
}
}

@ -25,6 +25,8 @@ class FunctionDef
public bool $method = false;
public bool $stub = false;
public bool $completed = false;
public bool $exactReturnType = false;
public string $returnClass = '';
public function __construct(string $name, string $returnType, string $namespace, bool $stub)
{

@ -116,8 +116,10 @@ class Preprocessor extends CompilerBase
case 'Stmt_Function':
$this->prepareFunction($v) . PHP_EOL;
break;
case 'Stmt_Declare':
case 'Stmt_Use':
$this->parseUse($v);
break;
case 'Stmt_Declare':
case 'Stmt_Interface':
case 'Stmt_Nop':
break;
@ -153,7 +155,8 @@ class Preprocessor extends CompilerBase
if ($call->class instanceof Node\Name) {
$className = $this->parseIdentifier($call->class);
if ($className !== 'self' && $className !== 'static') {
$this->symbolCallInFile[$this->file][] = strtolower($className);
$fullClassName = $this->getNamespacedClassName($className);
$this->symbolCallInFile[$this->file][] = strtolower($fullClassName);
}
}
}
@ -188,7 +191,6 @@ class Preprocessor extends CompilerBase
throw new Unsupported('Unsupported statement: ' . $type2);
}
}
$this->resetNamespace();
}
protected function prepareFunction(Node\Stmt\ClassMethod|Node\Stmt\Function_ $v): void

Loading…
Cancel
Save