refactor(php): 优化编译器基础类和预处理器逻辑

- 移除了未使用的 PropertyDef 导入声明
- 添加了 getRelativePath 方法用于获取相对路径
- 调整了方法调用返回类型检测的条件判断逻辑
- 修改了常量和别名解析的条件判断结构
- 重构了类继承检查逻辑,改进了内部类继承关系处理
- 更新了代码格式化时的路径显示为相对路径
- 重写了循环依赖解决算法的实现位置
- 修复了引用参数默认值的处理方式
- 统一了多个文件中的路径显示为相对路径格式
pull/1/head
韩天峰 5 months ago
parent d37c979031
commit 394c5ee0b7
  1. 25
      src/Php/CompilerBase.php
  2. 115
      src/Php/Preprocessor.php
  3. 4
      src/Php/Translator.php

@ -15,7 +15,6 @@ use PhpAot\Php\Entity\ConstantDef;
use PhpAot\Php\Entity\FunctionDef; use PhpAot\Php\Entity\FunctionDef;
use PhpAot\Php\Entity\InterfaceDef; use PhpAot\Php\Entity\InterfaceDef;
use PhpAot\Php\Entity\MethodDef; use PhpAot\Php\Entity\MethodDef;
use PhpAot\Php\Entity\PropertyDef;
use PhpAot\Php\Exception\DynamicCall; use PhpAot\Php\Exception\DynamicCall;
use PhpAot\Php\Exception\PlaceHolder; use PhpAot\Php\Exception\PlaceHolder;
use PhpAot\Php\Exception\Redo; use PhpAot\Php\Exception\Redo;
@ -563,6 +562,12 @@ class CompilerBase extends \PhpAot\Core\Translator
return false; return false;
} }
protected function getRelativePath($path, $cwd = ''): string
{
$cwd = $cwd ?: getcwd();
return ltrim($this->removeCommonPrefix($cwd, $path), '/');
}
protected function removeCommonPrefix(string $short, string $long): string protected function removeCommonPrefix(string $short, string $long): string
{ {
$len = min(strlen($short), strlen($long)); $len = min(strlen($short), strlen($long));
@ -1769,7 +1774,8 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($nativeFunc) { if ($nativeFunc) {
$funcDef = $this->functions[$nativeFunc]; $funcDef = $this->functions[$nativeFunc];
return $funcDef->returnType; return $funcDef->returnType;
} elseif ($this->isTypedObject($object)) { }
if ($this->isTypedObject($object)) {
return $this->detectMethodCallReturnType($this->getObjectType($object), $method); return $this->detectMethodCallReturnType($this->getObjectType($object), $method);
} }
} }
@ -3045,7 +3051,8 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
if ($this->isInternalConstant($name)) { if ($this->isInternalConstant($name)) {
return 'php::constant(' . $this->getLiteralString($name) . ')'; return 'php::constant(' . $this->getLiteralString($name) . ')';
} elseif (isset($this->useAliases[$name])) { }
if (isset($this->useAliases[$name])) {
$name = $this->useAliases[$name]; $name = $this->useAliases[$name];
} else { } else {
$fullName = $this->getNamespacedClassName($name); $fullName = $this->getNamespacedClassName($name);
@ -3133,14 +3140,18 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function isInheritedFrom(string $class, string $expected): bool protected function isInheritedFrom(string $class, string $expected): bool
{ {
if ($this->isInternalClass($class) and ($this->isInternalClass($expected) or $this->isInternalInterface($expected))) { $internal = ($this->isInternalClass($expected) or $this->isInternalInterface($expected));
return $class === $expected or is_subclass_of($class, $expected);
}
while (true) { while (true) {
if (strcasecmp($class, $expected) === 0) { if (strcasecmp($class, $expected) === 0) {
return true; return true;
} }
if (!$this->hasClass($class)) { if (!$this->hasClass($class)) {
// 原生类继承自一个内置类,例如: UserError extends Exception ,然后 $expected 预期是 Throwable
// 这种情况,需要使用 ZendVM 获取继承关系
if ($this->isInternalClass($class) and $internal) {
return $class === $expected or is_subclass_of($class, $expected);
}
return false; return false;
} }
$classDef = $this->getClass($class); $classDef = $this->getClass($class);
@ -3363,7 +3374,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function formatCppCode(string $file): void protected function formatCppCode(string $file): void
{ {
$cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file; $cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file;
$this->climate->info('format: ' . $file); $this->climate->info('format: ' . $this->getRelativePath($file));
$this->climate->comment($cmd); $this->climate->comment($cmd);
shell_exec($cmd); shell_exec($cmd);
} }

@ -74,61 +74,6 @@ class Preprocessor extends CompilerBase
$list = $sortedFiles; $list = $sortedFiles;
} }
/**
* 解决循环依赖问题
*
* @param array $fileDeps 所有文件的依赖关系
* @param array $circularNodes 循环依赖中的节点
* @return array 排序后的文件列表
* @throws ElementNotFoundException
*/
protected function resolveCircularDependencies(array $fileDeps, array $circularNodes): array
{
// 找出循环依赖中最少的边来打破循环
// 策略:移除被依赖次数最少的文件的依赖关系
$depCount = [];
foreach ($circularNodes as $node) {
$depCount[$node] = 0;
// 统计该节点在循环中被其他节点依赖的次数
foreach ($circularNodes as $otherNode) {
if (isset($fileDeps[$otherNode]) && in_array($node, $fileDeps[$otherNode])) {
$depCount[$node]++;
}
}
}
// 找到被依赖最少的节点,打破它的某个依赖
asort($depCount);
$breakNode = key($depCount);
$this->climate->darkGray("Breaking circular dependency at: {$breakNode}");
// 创建新的依赖关系,移除导致循环的依赖
$resolvedDeps = $fileDeps;
if (isset($resolvedDeps[$breakNode])) {
// 移除该节点对循环中其他节点的依赖
$resolvedDeps[$breakNode] = array_filter(
$resolvedDeps[$breakNode],
fn($dep) => !in_array($dep, $circularNodes) || $dep === $breakNode
);
}
// 使用修正后的依赖关系重新排序
$sorter = new StringSort();
foreach ($resolvedDeps as $file => $deps) {
$sorter->add($file, $deps);
}
try {
return $sorter->sort();
} catch (CircularDependencyException $e) {
// 如果仍然存在循环,递归处理
$remainingCircular = $e->getNodes();
$this->climate->yellow('Still has circular dependency, continuing to resolve...');
return $this->resolveCircularDependencies($resolvedDeps, $remainingCircular);
}
}
public function getCppFile(string $file): string public function getCppFile(string $file): string
{ {
$info = pathinfo($file); $info = pathinfo($file);
@ -172,7 +117,7 @@ class Preprocessor extends CompilerBase
$this->resetClass(); $this->resetClass();
$this->resetNamespace(); $this->resetNamespace();
$this->climate->info('prepare: ' . $this->file); $this->climate->info('prepare: ' . $this->getRelativePath($this->file));
try { try {
$ast = $this->parser->parse($phpCode); $ast = $this->parser->parse($phpCode);
} catch (\PhpParser\Error $e) { } catch (\PhpParser\Error $e) {
@ -215,7 +160,61 @@ class Preprocessor extends CompilerBase
$this->fatalError($v, 'Unsupported statement: ' . $type); $this->fatalError($v, 'Unsupported statement: ' . $type);
} }
} }
}
/**
* 解决循环依赖问题
*
* @param array $fileDeps 所有文件的依赖关系
* @param array $circularNodes 循环依赖中的节点
* @return array 排序后的文件列表
* @throws ElementNotFoundException
*/
protected function resolveCircularDependencies(array $fileDeps, array $circularNodes): array
{
// 找出循环依赖中最少的边来打破循环
// 策略:移除被依赖次数最少的文件的依赖关系
$depCount = [];
foreach ($circularNodes as $node) {
$depCount[$node] = 0;
// 统计该节点在循环中被其他节点依赖的次数
foreach ($circularNodes as $otherNode) {
if (isset($fileDeps[$otherNode]) && in_array($node, $fileDeps[$otherNode])) {
$depCount[$node]++;
}
}
}
// 找到被依赖最少的节点,打破它的某个依赖
asort($depCount);
$breakNode = key($depCount);
$this->climate->darkGray("Breaking circular dependency at: {$breakNode}");
// 创建新的依赖关系,移除导致循环的依赖
$resolvedDeps = $fileDeps;
if (isset($resolvedDeps[$breakNode])) {
// 移除该节点对循环中其他节点的依赖
$resolvedDeps[$breakNode] = array_filter(
$resolvedDeps[$breakNode],
fn ($dep) => !in_array($dep, $circularNodes) || $dep === $breakNode
);
}
// 使用修正后的依赖关系重新排序
$sorter = new StringSort();
foreach ($resolvedDeps as $file => $deps) {
$sorter->add($file, $deps);
}
try {
return $sorter->sort();
} catch (CircularDependencyException $e) {
// 如果仍然存在循环,递归处理
$remainingCircular = $e->getNodes();
$this->climate->yellow('Still has circular dependency, continuing to resolve...');
return $this->resolveCircularDependencies($resolvedDeps, $remainingCircular);
}
} }
protected function findSymbolUsing(NodeAbstract $ast) protected function findSymbolUsing(NodeAbstract $ast)
@ -356,7 +355,7 @@ class Preprocessor extends CompilerBase
$argInfo->default = 'nullptr'; $argInfo->default = 'nullptr';
$argInfo->defaultValue = null; $argInfo->defaultValue = null;
} else { } else {
$this->fatalError($param, 'Only null and empty array can be used as default value for reference parameter'); $argInfo->default = 'php::newReference(' . $this->parseParamDefaultValue($param->default) . ')';
} }
} else { } else {
$argInfo->default = $this->parseParamDefaultValue($param->default); $argInfo->default = $this->parseParamDefaultValue($param->default);
@ -453,7 +452,7 @@ class Preprocessor extends CompilerBase
if ($class instanceof Node\Stmt\Enum_) { if ($class instanceof Node\Stmt\Enum_) {
$flags = Modifiers::PUBLIC; $flags = Modifiers::PUBLIC;
} else if (!$class instanceof Node\Stmt\Trait_) { } elseif (!$class instanceof Node\Stmt\Trait_) {
$flags = $class->flags; $flags = $class->flags;
} else { } else {
$flags = Modifiers::PUBLIC; $flags = Modifiers::PUBLIC;

@ -662,7 +662,7 @@ class Translator extends Preprocessor
protected function doConvert(string $phpCode): string protected function doConvert(string $phpCode): string
{ {
$this->climate->info('convert: ' . $this->file); $this->climate->info('convert: ' . $this->getRelativePath($this->file));
$ast = $this->parser->parse($phpCode); $ast = $this->parser->parse($phpCode);
$traverser = new NodeTraverser(); $traverser = new NodeTraverser();
@ -855,7 +855,7 @@ class Translator extends Preprocessor
$genStubCmd = PHP_BINARY . ' ' . $this->rootPath . '/bin/gen_stub.php -f -o ' . $this->getIncludeDir() . '/' . $headerFile . ' ' . $file; $genStubCmd = PHP_BINARY . ' ' . $this->rootPath . '/bin/gen_stub.php -f -o ' . $this->getIncludeDir() . '/' . $headerFile . ' ' . $file;
$output = shell_exec($genStubCmd); $output = shell_exec($genStubCmd);
$this->climate->info('generate stub file: ' . $file); $this->climate->info('generate stub file: ' . $this->getRelativePath($file));
$this->climate->comment($genStubCmd); $this->climate->comment($genStubCmd);
if (!str_contains($output, 'Saved')) { if (!str_contains($output, 'Saved')) {

Loading…
Cancel
Save