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

- 移除了未使用的 PropertyDef 导入声明
- 添加了 getRelativePath 方法用于获取相对路径
- 调整了方法调用返回类型检测的条件判断逻辑
- 修改了常量和别名解析的条件判断结构
- 重构了类继承检查逻辑,改进了内部类继承关系处理
- 更新了代码格式化时的路径显示为相对路径
- 重写了循环依赖解决算法的实现位置
- 修复了引用参数默认值的处理方式
- 统一了多个文件中的路径显示为相对路径格式
pull/1/head
韩天峰 5 months ago
parent d37c979031
commit 394c5ee0b7
  1. 25
      src/Php/CompilerBase.php
  2. 119
      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\InterfaceDef;
use PhpAot\Php\Entity\MethodDef;
use PhpAot\Php\Entity\PropertyDef;
use PhpAot\Php\Exception\DynamicCall;
use PhpAot\Php\Exception\PlaceHolder;
use PhpAot\Php\Exception\Redo;
@ -563,6 +562,12 @@ class CompilerBase extends \PhpAot\Core\Translator
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
{
$len = min(strlen($short), strlen($long));
@ -1769,7 +1774,8 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($nativeFunc) {
$funcDef = $this->functions[$nativeFunc];
return $funcDef->returnType;
} elseif ($this->isTypedObject($object)) {
}
if ($this->isTypedObject($object)) {
return $this->detectMethodCallReturnType($this->getObjectType($object), $method);
}
}
@ -3045,7 +3051,8 @@ class CompilerBase extends \PhpAot\Core\Translator
}
if ($this->isInternalConstant($name)) {
return 'php::constant(' . $this->getLiteralString($name) . ')';
} elseif (isset($this->useAliases[$name])) {
}
if (isset($this->useAliases[$name])) {
$name = $this->useAliases[$name];
} else {
$fullName = $this->getNamespacedClassName($name);
@ -3133,14 +3140,18 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function isInheritedFrom(string $class, string $expected): bool
{
if ($this->isInternalClass($class) and ($this->isInternalClass($expected) or $this->isInternalInterface($expected))) {
return $class === $expected or is_subclass_of($class, $expected);
}
$internal = ($this->isInternalClass($expected) or $this->isInternalInterface($expected));
while (true) {
if (strcasecmp($class, $expected) === 0) {
return true;
}
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;
}
$classDef = $this->getClass($class);
@ -3363,7 +3374,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function formatCppCode(string $file): void
{
$cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file;
$this->climate->info('format: ' . $file);
$this->climate->info('format: ' . $this->getRelativePath($file));
$this->climate->comment($cmd);
shell_exec($cmd);
}

@ -59,7 +59,7 @@ class Preprocessor extends CompilerBase
$this->climate->yellow('Warning: Circular dependency detected, attempting to resolve...');
$circularNodes = $e->getNodes();
$this->climate->darkGray('Circular path: ' . implode(' -> ', $circularNodes));
// 使用打破循环后的依赖关系重新排序
$sortedFiles = $this->resolveCircularDependencies($fileDeps, $circularNodes);
}
@ -70,63 +70,8 @@ class Preprocessor extends CompilerBase
$sortedFiles[] = $file;
}
}
$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);
}
$list = $sortedFiles;
}
public function getCppFile(string $file): string
@ -172,7 +117,7 @@ class Preprocessor extends CompilerBase
$this->resetClass();
$this->resetNamespace();
$this->climate->info('prepare: ' . $this->file);
$this->climate->info('prepare: ' . $this->getRelativePath($this->file));
try {
$ast = $this->parser->parse($phpCode);
} catch (\PhpParser\Error $e) {
@ -215,7 +160,61 @@ class Preprocessor extends CompilerBase
$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)
@ -356,7 +355,7 @@ class Preprocessor extends CompilerBase
$argInfo->default = 'nullptr';
$argInfo->defaultValue = null;
} 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 {
$argInfo->default = $this->parseParamDefaultValue($param->default);
@ -453,7 +452,7 @@ class Preprocessor extends CompilerBase
if ($class instanceof Node\Stmt\Enum_) {
$flags = Modifiers::PUBLIC;
} else if (!$class instanceof Node\Stmt\Trait_) {
} elseif (!$class instanceof Node\Stmt\Trait_) {
$flags = $class->flags;
} else {
$flags = Modifiers::PUBLIC;

@ -662,7 +662,7 @@ class Translator extends Preprocessor
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);
$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;
$output = shell_exec($genStubCmd);
$this->climate->info('generate stub file: ' . $file);
$this->climate->info('generate stub file: ' . $this->getRelativePath($file));
$this->climate->comment($genStubCmd);
if (!str_contains($output, 'Saved')) {

Loading…
Cancel
Save