refactor(php): 重构PHP编译器依赖管理和类属性初始化功能

- 移除ClosureGenerator中无用的方法注释
- 在CompilerBase中重命名参数并添加isInternalClass方法
- 从ConstantDef中移除无用的导入
- 完全删除FileSorter类,改用外部库MJS\TopSort进行文件排序
- 在Preprocessor中重构依赖收集逻辑,优化文件排序算法
- 过滤内置函数和类,避免参与依赖管理
- 重构Translator中的类属性初始化代码,优化对象创建流程
- 统一字符串拼接操作符为单引号格式
pull/1/head
韩天峰 5 months ago
parent bb52f8ab10
commit f6a3e5b4b3
  1. 14
      src/Php/CompilerBase.php
  2. 2
      src/Php/Entity/ConstantDef.php
  3. 100
      src/Php/FileSorter.php
  4. 7
      src/Php/Generator/ClosureGenerator.php
  5. 42
      src/Php/Preprocessor.php
  6. 62
      src/Php/Translator.php

@ -245,6 +245,7 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string, bool>
*/
protected array $classMethodOverride = [];
/**
* 存储所有类继承关系,类名必须全部为小写
* @var array<string, string>
@ -1398,9 +1399,14 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->isNativeType($this->getVarType($var));
}
protected function isInternalFunction(string $fname): bool
protected function isInternalFunction(string $name): bool
{
return array_key_exists($name, $this->internalFunctions);
}
protected function isInternalClass(string $name): bool
{
return array_key_exists($fname, $this->internalFunctions);
return Reflection::isInternalClass($name);
}
protected function isAssignOpConcat(string $op): bool
@ -4322,7 +4328,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseArrowFunction(Node\Expr\ArrowFunction $expr): string
{
$nodeFinder = new NodeFinder();
$vars = $nodeFinder->findInstanceOf($expr->expr, Node\Expr\Variable::class);
$vars = $nodeFinder->findInstanceOf($expr->expr, Variable::class);
$uses = [];
$params = [];
@ -4330,7 +4336,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($param->byRef) {
$this->fatalError($expr, 'Closure cannot use reference parameter');
}
if ($param->var instanceof Node\Expr\Variable) {
if ($param->var instanceof Variable) {
$params[$param->var->name] = $i;
}
}

@ -8,8 +8,6 @@
namespace PhpAot\Php\Entity;
use PhpParser\Node\Expr;
class ConstantDef
{
public string $name;

@ -1,100 +0,0 @@
<?php
/**
* This file is part of Swoole-Compiler(AOT).
*
* @link https://www.swoole.com/
* @contact service@swoole.com
*/
namespace PhpAot\Php;
class FileSorter
{
private array $symbolDeclInFile;
private array $symbolCallInFile;
public function __construct(array $symbolDeclInFile, array $symbolCallInFile)
{
$this->symbolDeclInFile = $symbolDeclInFile;
$this->symbolCallInFile = $symbolCallInFile;
}
public function sort(): array
{
$dependencies = $this->buildDependencies();
$allFiles = $this->getAllFiles();
$inDegree = array_fill_keys($allFiles, 0);
foreach ($dependencies as $deps) {
foreach ($deps as $dep) {
$inDegree[$dep]++;
}
}
$queue = [];
foreach ($inDegree as $file => $degree) {
if ($degree === 0) {
$queue[] = $file;
}
}
$sorted = [];
while (!empty($queue)) {
$current = array_shift($queue);
$sorted[] = $current;
if (isset($dependencies[$current])) {
foreach ($dependencies[$current] as $dep) {
$inDegree[$dep]--;
if ($inDegree[$dep] === 0) {
$queue[] = $dep;
}
}
}
}
if (count($sorted) !== count($allFiles)) {
throw new \RuntimeException('Circular dependency of function call detected');
}
return array_reverse($sorted);
}
private function buildDependencies(): array
{
$dependencies = [];
foreach ($this->symbolCallInFile as $call) {
$callerFile = $call['file'];
$symbolName = $call['name'];
if (isset($this->symbolDeclInFile[$symbolName])) {
$declFile = $this->symbolDeclInFile[$symbolName];
if ($callerFile !== $declFile) {
if (!isset($dependencies[$callerFile])) {
$dependencies[$callerFile] = [];
}
if (!in_array($declFile, $dependencies[$callerFile])) {
$dependencies[$callerFile][] = $declFile;
}
}
}
}
return $dependencies;
}
private function getAllFiles(): array
{
$files = array_values($this->symbolDeclInFile);
foreach ($this->symbolCallInFile as $call) {
$files[] = $call['file'];
}
return array_unique($files);
}
}

@ -21,13 +21,6 @@ trait ClosureGenerator
return $code;
}
/**
* @param NodeAbstract $expr
* @param array $params
* @param callable $bodyGenCb
* @param array $uses
* @return string
*/
protected function genClosure(NodeAbstract $expr, array $params, callable $bodyGenCb, array $uses = []): string
{
$tmpVar = $this->genTmpVarName();

@ -8,6 +8,7 @@
namespace PhpAot\Php;
use MJS\TopSort\Implementations\StringSort;
use PhpAot\Php\Exception\SyntaxError;
use PhpParser\Node;
use PhpParser\NodeAbstract;
@ -20,12 +21,16 @@ class Preprocessor extends CompilerBase
public function sortFiles(array &$list): void
{
foreach ($this->symbolCallInFile as $k => $call) {
if (!isset($this->symbolDeclInFile[$call['name']])) {
unset($this->symbolCallInFile[$k]);
$sorter = new StringSort();
foreach ($this->symbolCallInFile as $file => $symbols) {
$deps = [];
foreach ($symbols as $symbol) {
if (isset($this->symbolDeclInFile[$symbol])) {
$deps[] = $this->symbolDeclInFile[$symbol];
}
}
$sorter->add($file, array_unique($deps));
}
$sorter = new FileSorter($this->symbolDeclInFile, $this->symbolCallInFile);
$sortedFiles = $sorter->sort();
foreach ($list as $file) {
@ -72,6 +77,7 @@ class Preprocessor extends CompilerBase
}
$phpCode = $this->loadFile($file);
$this->symbolCallInFile[$this->file] = [];
$this->climate->info('prepare: ' . $this->file);
try {
@ -120,12 +126,11 @@ class Preprocessor extends CompilerBase
foreach ($functionCalls as $call) {
if ($call->name instanceof Node\Name) {
$name = $call->name->toString();
$this->symbolCallInFile[] = [
'name' => strtolower($name),
'file' => $this->file,
'line' => $call->getLine(),
];
// 内置函数不参与依赖管理
$funcName = strtolower($call->name->toString());
if (!$this->isInternalFunction($funcName)) {
$this->symbolCallInFile[$this->file][] = $funcName;
}
}
}
}
@ -145,6 +150,8 @@ class Preprocessor extends CompilerBase
$this->prepareFunction($v2) . PHP_EOL;
break;
case 'Stmt_Use':
$this->parseUse($v2);
break;
case 'Stmt_Const':
case 'Stmt_Interface':
break;
@ -164,7 +171,9 @@ class Preprocessor extends CompilerBase
if ($this->stubFile) {
$this->nativeFunctions[$name] = $this->parseFunctionDecl($v);
} else {
$this->symbolDeclInFile[strtolower($name)] = $this->file;
if ($v instanceof Node\Stmt\Function_) {
$this->symbolDeclInFile[strtolower($name)] = $this->file;
}
}
}
@ -182,19 +191,18 @@ class Preprocessor extends CompilerBase
$this->class = $this->parseIdentifier($class->name);
$fullClassName = $this->getNamespacedClassName($this->class);
$fullClassNameLower = strtolower($fullClassName);
if (!empty($class->extends)) {
$this->parentClass = $this->getParentClass($class->extends);
$parentClassLower = strtolower($this->parentClass);
$this->symbolCallInFile[] = [
'name' => $parentClassLower,
'file' => $this->file,
'line' => $class->getLine(),
];
$this->classExtends[$fullClassNameLower] = $parentClassLower;
if (!$this->isInternalClass($parentClassLower)) {
$this->symbolCallInFile[$this->file][] = $parentClassLower;
}
}
$this->symbolDeclInFile[$fullClassNameLower] = $this->file;
$code = '';
$code = '';
foreach ($class->stmts as $v) {
$type = $v->getType();
switch ($type) {

@ -32,8 +32,10 @@ class Translator extends Preprocessor
protected array $phpSrcFiles = [];
protected array $argInfoHeaderFiles = [];
protected array $registerSymbols = [];
// 类静态属性初始值
protected array $defaultStaticPropertyList = [];
// 类属性初始值
protected array $defaultPropertyList = [];
protected bool $useRegisterSymbolsFn = false;
@ -494,6 +496,35 @@ class Translator extends Preprocessor
return implode(PHP_EOL, $lines) . PHP_EOL . PHP_EOL;
}
public function genClassPropertyInit(): string
{
$code = '';
foreach ($this->classCeList as $ce) {
$info = $this->classCeInfo[$ce] ?? $this->getInternalCeInfo($ce);
$code .= "{$ce} = {$info['func']}({$info['args']});\n";
$classDef = !empty($info['classDef']) ? $info['classDef'] : null;
/**
* @var ClassDef $classDef
*/
if ($classDef and $classDef->requireCtor) {
$className = $classDef->getNamespacedName();
$code .= "create_object_{$className} = php_get_create_object_fn({$ce});\n";
$code .= "{$ce}->create_object = [](zend_class_entry *class_type) -> zend_object* {\n";
$code .= "auto obj = create_object_{$className}(class_type);\n";
foreach ($classDef->properties as $property) {
$fullPropName = $classDef->getNamespacedName() . '::' . $property->name;
if (isset($this->defaultPropertyList[$fullPropName])) {
$code .= "auto value = {$this->defaultPropertyList[$fullPropName]};\n";
$code .= 'zend_update_property_ex(obj->ce, obj, ' . $this->getLiteralString($property->name) . ".str(), value.ptr());\n";
}
}
$code .= "return obj;\n};\n";
}
}
return $code;
}
protected function getRegisterClassFunction(string $name): string
{
return self::PREFIX . 'register_class_' . $name;
@ -527,35 +558,6 @@ class Translator extends Preprocessor
return $scanner->scan();
}
public function genClassPropertyInit(): string
{
$code = '';
foreach ($this->classCeList as $ce) {
$info = $this->classCeInfo[$ce] ?? $this->getInternalCeInfo($ce);
$code .= "$ce = {$info['func']}({$info['args']});\n";
$classDef = !empty($info['classDef']) ? $info['classDef'] : null;
/**
* @var ClassDef $classDef
*/
if ($classDef and $classDef->requireCtor) {
$className = $classDef->getNamespacedName();
$code .= "create_object_$className = php_get_create_object_fn($ce);\n";
$code .= "{$ce}->create_object = [](zend_class_entry *class_type) -> zend_object* {\n";
$code .= "auto obj = create_object_$className(class_type);\n";
foreach ($classDef->properties as $property) {
$fullPropName = $classDef->getNamespacedName() . '::' . $property->name;
if (isset($this->defaultPropertyList[$fullPropName])) {
$code .= "auto value = {$this->defaultPropertyList[$fullPropName]};\n";
$code .= "zend_update_property_ex(obj->ce, obj, " . $this->getLiteralString($property->name) . ".str(), value.ptr());\n";
}
}
$code .= "return obj;\n};\n";
}
}
return $code;
}
protected function genClassArrayConstants(): string
{
$code = '';
@ -565,7 +567,7 @@ class Translator extends Preprocessor
$constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name);
$code .= "do {\n";
$code .= $constant->arrayExpr;
$code .= $constName . " = " . $constant->value . ";\n";
$code .= $constName . ' = ' . $constant->value . ";\n";
$code .= "} while(0);\n";
}
}

Loading…
Cancel
Save