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

@ -32,33 +32,34 @@ trait MagicMethodDetector
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument");
} }
} elseif ($nameLower == '__tostring') { } 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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return string");
} }
} elseif ($nameLower == '__serialize') { } 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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
} }
} elseif ($nameLower == '__unserialize') { } elseif ($nameLower == '__unserialize') {
if (count($argInfoList) != 1) { if (count($argInfoList) != 1) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); $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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take array as argument");
} }
} elseif ($nameLower == '__isset' or $nameLower == '__unset' or $nameLower == '__set_state') { } elseif ($nameLower == '__isset' or $nameLower == '__unset' or $nameLower == '__set_state') {
if (count($argInfoList) != 1) { if (count($argInfoList) != 1) {
$this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); $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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take string as argument");
} }
if ($nameLower == '__set_state') { 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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
} }
} }
} elseif ($nameLower == '__debuginfo') { } 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"); $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return array");
} }
} }

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

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

Loading…
Cancel
Save