refactor(php): 优化PHP编译器代码结构和类型检查逻辑

- 修改clone表达式解析为使用php::clone函数调用
- 更新属性获取表达式的对象转换方式
- 使用checkArgType方法替代直接的类型比较进行魔术方法验证
- 重构预处理器中的方法准备逻辑以跳过抽象方法
- 添加Modifiers导入并改进依赖排序逻辑
- 为genNativeMethod方法参数添加类型声明
pull/1/head
韩天峰 5 months ago
parent 67275c45f7
commit 7dd30e2908
  1. 4
      src/Php/CompilerBase.php
  2. 13
      src/Php/MagicMethodDetector.php
  3. 34
      src/Php/Preprocessor.php
  4. 2
      src/Php/Translator.php

@ -2909,7 +2909,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseClone(Node\Expr\Clone_ $expr): string
{
return $this->convertToObject($expr->expr) . '.clone()';
return 'php::clone('.$this->parseExpr($expr->expr).')';
}
protected function parseInstanceof(Node\Expr\Instanceof_ $expr): string
@ -3640,7 +3640,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
if ($this->isPropertyFetch($expr->expr)) {
$left = $this->parseIdentifier($expr->var);
$object = $this->convertToObject($expr->expr->var);
$object = $this->parseExpr($expr->expr->var);
$prop = $this->identifierToStr($expr->expr->name);
return $left . ' = ' . $object . '.attrRef(' . $prop . ')';

@ -32,33 +32,34 @@ trait MagicMethodDetector
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument");
}
} elseif ($nameLower == '__tostring') {
if ($returnType != self::TYPE_VAR and $returnType != self::TYPE_STR) {
if (!$this->checkArgType($returnType, self::TYPE_STR)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return string");
}
} elseif ($nameLower == '__serialize') {
if ($returnType != self::TYPE_VAR and $returnType != self::TYPE_ARRAY) {
if (!$this->checkArgType($returnType, self::TYPE_ARRAY)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
}
} elseif ($nameLower == '__unserialize') {
if (count($argInfoList) != 1) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument");
} elseif (!$argInfoList[0]->type or $argInfoList[0]->type != self::TYPE_ARRAY) {
}
if (!$this->checkArgType($argInfoList[0]->type, self::TYPE_ARRAY)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take array as argument");
}
} elseif ($nameLower == '__isset' or $nameLower == '__unset' or $nameLower == '__set_state') {
if (count($argInfoList) != 1) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument");
}
if (!$argInfoList[0]->type or $argInfoList[0]->type != self::TYPE_STR) {
if (!$this->checkArgType($argInfoList[0]->type, self::TYPE_STR)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take string as argument");
}
if ($nameLower == '__set_state') {
if (!$returnType or $returnType != self::TYPE_ARRAY) {
if (!$this->checkArgType($returnType, self::TYPE_ARRAY)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
}
}
} elseif ($nameLower == '__debuginfo') {
if (!$returnType or $returnType != self::TYPE_ARRAY) {
if (!$this->checkArgType($returnType, self::TYPE_ARRAY)) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
}
}

@ -10,6 +10,7 @@ namespace PhpAot\Php;
use MJS\TopSort\Implementations\StringSort;
use PhpAot\Php\Exception\SyntaxError;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\NodeAbstract;
use PhpParser\NodeFinder;
@ -22,6 +23,7 @@ class Preprocessor extends CompilerBase
public function sortFiles(array &$list): void
{
$sorter = new StringSort();
foreach ($this->symbolCallInFile as $file => $symbols) {
$deps = [];
foreach ($symbols as $symbol) {
@ -232,22 +234,24 @@ class Preprocessor extends CompilerBase
protected function prepareMethod(Node\Stmt\ClassMethod $v): void
{
$this->prepareFunction($v) . PHP_EOL;
if ($this->isIdExpr($v->name) or $this->isNameExpr($v->name)) {
$fullClassName = $this->getNamespacedClassName($this->class);
$fullMethodName = $fullClassName . '::' . $v->name;
$this->classMethodOverride[strtolower($fullMethodName)] = false;
// 查找父类是否有同名方法,递归查找
$fullClassNameLower = strtolower($fullClassName);
while (isset($this->classExtends[$fullClassNameLower])) {
$parentClass = $this->classExtends[$fullClassNameLower];
$parentMethodLower = strtolower($parentClass . '::' . $v->name);
// 父类有同名方法,子类覆盖了父类方法,这种情况不能直接使用 C++ 函数,而是使用 ZendVM 动态调用
if (isset($this->classMethodOverride[$parentMethodLower])) {
$this->classMethodOverride[$parentMethodLower] = true;
}
$fullClassNameLower = strtolower($parentClass);
$abstract = $v->flags & Modifiers::ABSTRACT;
if (!$abstract) {
$this->prepareFunction($v) . PHP_EOL;
}
$fullClassName = $this->getNamespacedClassName($this->class);
$fullMethodName = $fullClassName . '::' . $v->name;
$this->classMethodOverride[strtolower($fullMethodName)] = false;
// 查找父类是否有同名方法,递归查找
$fullClassNameLower = strtolower($fullClassName);
while (isset($this->classExtends[$fullClassNameLower])) {
$parentClass = $this->classExtends[$fullClassNameLower];
$parentMethodLower = strtolower($parentClass . '::' . $v->name);
// 父类有同名方法,子类覆盖了父类方法,这种情况不能直接使用 C++ 函数,而是使用 ZendVM 动态调用
if (isset($this->classMethodOverride[$parentMethodLower])) {
$this->classMethodOverride[$parentMethodLower] = true;
}
$fullClassNameLower = strtolower($parentClass);
}
}
}

@ -927,7 +927,7 @@ class Translator extends Preprocessor
return $code;
}
protected function genNativeMethod($methodCodes): string
protected function genNativeMethod(array $methodCodes): string
{
$code = '';
$classDef = $this->classDef;

Loading…
Cancel
Save