feat(compiler): 添加符号声明和调用跟踪功能并优化方法调用检查

- 添加 symbolDeclInFile 和 symbolCallInFile 属性用于存储函数和类方法的声明及调用信息
- 修改 getNativeMethod 方法增加 checkArgs 参数控制参数检查逻辑
- 优化 Match 表达式解析逻辑,支持非变量条件表达式的处理
- 移除未处理匹配情况时不必要的返回空值语句
- 在预处理器中添加对静态调用、静态属性访问、类常量获取和新对象创建的依赖类跟踪
- 修复抽象类实例化错误消息中的字符串插值语法
- 为动态调用场景禁用参数检查以避免误报错误
pull/1/head
韩天峰 5 months ago
parent eb2eacc69a
commit ddeceec91f
  1. 38
      src/Php/CompilerBase.php
  2. 15
      src/Php/Preprocessor.php

@ -143,7 +143,17 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $nativeFunctions = [];
protected array $internalFunctions = [];
protected array $nativeConstants = [];
/**
* 存储所有函数、类方法的声明,key 是 符号名称,Value 是函数、类方法所在的文件名称
* @var array<string, string>
*/
protected array $symbolDeclInFile = [];
/**
* 存储所有函数、类方法的调用,key 是 文件名称,Value 是函数、类方法调用的列表数组
* @var array<string, array<string>>
*/
protected array $symbolCallInFile = [];
protected array $redoAfterDeclare = [];
protected array $constData = [];
@ -1650,7 +1660,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
}
protected function getNativeMethod(CallLike $expr, string $class, string $method): string|false
protected function getNativeMethod(CallLike $expr, string $class, string $method, bool $checkArgs = true): string|false
{
if (!$this->hasNativeClass($class)) {
return false;
@ -1690,7 +1700,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) {
return false;
}
$this->checkNativeCallArgs($expr, $methodDef->functionDef, $expr->args, $classDef->getNamespacedName() . '::' . $method);
if ($checkArgs) {
$this->checkNativeCallArgs($expr, $methodDef->functionDef, $expr->args, $classDef->getNamespacedName() . '::' . $method);
}
return $this->getNativeName($method, $classDef->namespace, $classDef->name);
}
@ -1737,7 +1749,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$oriType = $this->functionDef->returnType;
$this->functionDef->returnType = $type;
// 返回值变更,需要重新解析
$this->climate->cyan("Return type changed ($oriType -> $type) at line {$node->getLine()} retrying...");
$this->climate->cyan("Return type changed ({$oriType} -> {$type}) at line {$node->getLine()} retrying...");
throw new Redo();
}
@ -2606,9 +2618,16 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseMatch(Node\Expr\Match_ $expr): string
{
$var = $this->parseIdentifier($expr->cond);
if ($this->isVarExpr($expr->cond) and !$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->cond);
if ($this->isVarExpr($expr->cond)) {
if (!$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->cond);
}
} else {
$tmpVar = $this->addTmpVar(self::TYPE_VAR);
$this->context->beforeStmtLines[] = $tmpVar . ' = ' . $var . ';';
$var = $tmpVar;
}
$code = '[&]() -> ' . self::TYPE_VAR . '{';
$default = null;
foreach ($expr->arms as $i => $arm) {
@ -2633,8 +2652,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($default) {
$code .= $else . ' { return ' . $this->parseExpr($default) . '; }';
} else {
$code .= $else . ' { php::throwException("UnhandledMatchError", "Unhandled match case");' . PHP_EOL .
'return ' . self::VALUE_NULL . '; }';
$code .= $else . ' { return php::throwException("UnhandledMatchError", "Unhandled match case"); }';
}
$code .= '}()';
@ -2929,7 +2947,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->hasNativeClass($className)) {
$classDef = $this->getClassDef($className);
if ($classDef->flags & Modifiers::ABSTRACT) {
$this->fatalError($expr, "abstract class `$className` cannot be instantiated");
$this->fatalError($expr, "abstract class `{$className}` cannot be instantiated");
}
}
$cePtr = $this->getClassEntryPtr($className);
@ -3820,7 +3838,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($callScope) {
$nativeFunc = $this->getNativeMethod($expr, $class, $method);
// 存在 Native 类,但是没有找到方法,可能是动态调用
if (!$nativeFunc and $this->hasNativeClass($class) and $this->getNativeMethod($expr, $class, '__callStatic')) {
if (!$nativeFunc and $this->hasNativeClass($class) and $this->getNativeMethod($expr, $class, '__callStatic', false)) {
$dynamicCall = true;
}
@ -4271,7 +4289,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$class = $this->context->objects[$object];
$nativeFunc = $this->getNativeMethod($expr, $class, $method);
// 存在 Native 类,但是没有找到方法,可能是动态调用
if (!$nativeFunc and $this->hasNativeClass($class) and $this->getNativeMethod($expr, $class, '__call')) {
if (!$nativeFunc and $this->hasNativeClass($class) and $this->getNativeMethod($expr, $class, '__call', false)) {
throw new DynamicCall();
}
}

@ -144,6 +144,21 @@ class Preprocessor extends CompilerBase
}
}
}
$depClasses = $nodeFinder->findInstanceOf($ast, Node\Expr\StaticCall::class);
$depClasses = array_merge($depClasses, $nodeFinder->findInstanceOf($ast, Node\Expr\StaticPropertyFetch::class));
$depClasses = array_merge($depClasses, $nodeFinder->findInstanceOf($ast, Node\Expr\ClassConstFetch::class));
$depClasses = array_merge($depClasses, $nodeFinder->findInstanceOf($ast, Node\Expr\New_::class));
foreach ($depClasses as $call) {
if ($call->class instanceof Node\Name) {
$className = $this->parseIdentifier($call->class);
if ($className !== 'self' && $className !== 'static') {
$this->symbolCallInFile[$this->file][] = strtolower($className);
}
}
}
// 依赖去重
$this->symbolCallInFile[$this->file] = array_unique($this->symbolCallInFile[$this->file]);
}
protected function prepareNamespaceDef(Node\Stmt\Namespace_ $node): void

Loading…
Cancel
Save