diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index b04ccf55..ebc75a9a 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -245,6 +245,7 @@ class CompilerBase extends \PhpAot\Core\Translator * @var array */ protected array $classMethodOverride = []; + /** * 存储所有类继承关系,类名必须全部为小写 * @var array @@ -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; } } diff --git a/src/Php/Entity/ConstantDef.php b/src/Php/Entity/ConstantDef.php index 154fa6ac..d8d4b402 100644 --- a/src/Php/Entity/ConstantDef.php +++ b/src/Php/Entity/ConstantDef.php @@ -8,8 +8,6 @@ namespace PhpAot\Php\Entity; -use PhpParser\Node\Expr; - class ConstantDef { public string $name; diff --git a/src/Php/FileSorter.php b/src/Php/FileSorter.php deleted file mode 100644 index 686d14af..00000000 --- a/src/Php/FileSorter.php +++ /dev/null @@ -1,100 +0,0 @@ -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); - } -} diff --git a/src/Php/Generator/ClosureGenerator.php b/src/Php/Generator/ClosureGenerator.php index dafb7339..811684b3 100644 --- a/src/Php/Generator/ClosureGenerator.php +++ b/src/Php/Generator/ClosureGenerator.php @@ -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(); diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index 82c66a82..123ec91c 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -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) { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 8ccbabf5..391332a3 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -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"; } }