Interface,ce 依赖关系处理,排序

pull/1/head
韩天峰 7 months ago
parent f8100988c4
commit 6ff687e1da
  1. 3
      composer.json
  2. 64
      composer.lock
  3. 3
      src/Php/ClassLikeDef.php
  4. 12
      src/Php/CompilerBase.php
  5. 79
      src/Php/Translator.php
  6. 34
      src/template/extension.cc.php

@ -1,7 +1,8 @@
{ {
"require": { "require": {
"nikic/php-parser": "5.6.1", "nikic/php-parser": "5.6.1",
"league/climate": "^3.10" "league/climate": "^3.10",
"marcj/topsort": "^2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.4", "phpunit/phpunit": "^10.4",

64
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "dff0db7b08aac2e595d7436d35f1ac3c", "content-hash": "d4e35915568beccdcd533360bf30a206",
"packages": [ "packages": [
{ {
"name": "league/climate", "name": "league/climate",
@ -72,6 +72,68 @@
}, },
"time": "2024-11-18T09:09:55+00:00" "time": "2024-11-18T09:09:55+00:00"
}, },
{
"name": "marcj/topsort",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/marcj/topsort.php.git",
"reference": "972f58e42b5f110a0a1d8433247f65248abcfd5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/marcj/topsort.php/zipball/972f58e42b5f110a0a1d8433247f65248abcfd5c",
"reference": "972f58e42b5f110a0a1d8433247f65248abcfd5c",
"shasum": ""
},
"require": {
"php": ">=7.3"
},
"require-dev": {
"codeclimate/php-test-reporter": "dev-master",
"phpunit/phpunit": "^9",
"symfony/console": "~2.5 || ~3.0 || ~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"MJS\\TopSort\\": "src/",
"MJS\\TopSort\\Tests\\": "tests/Tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marc J. Schmidt",
"email": "marc@marcjschmidt.de"
}
],
"description": "High-Performance TopSort/Dependency resolving algorithm",
"keywords": [
"dependency resolving",
"topological sort",
"topsort"
],
"support": {
"issues": "https://github.com/marcj/topsort.php/issues",
"source": "https://github.com/marcj/topsort.php/tree/2.0.0"
},
"funding": [
{
"url": "https://github.com/marcj",
"type": "github"
}
],
"time": "2020-09-24T12:39:55+00:00"
},
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v5.6.1", "version": "v5.6.1",

@ -5,7 +5,8 @@ namespace PhpAot\Php;
class ClassLikeDef class ClassLikeDef
{ {
public string $name; public string $name;
public string $namespace = ''; public string $namespace;
public string $extends = '';
public function __construct(string $name, string $namespace = '') public function __construct(string $name, string $namespace = '')
{ {

@ -82,6 +82,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $useNamespaces = []; protected array $useNamespaces = [];
protected array $useFunctions = []; protected array $useFunctions = [];
protected string $class = ''; protected string $class = '';
protected string $interface = '';
/** /**
* @var array<string, ClassDef> * @var array<string, ClassDef>
*/ */
@ -91,8 +92,18 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string, ClassDef> * @var array<string, ClassDef>
*/ */
protected array $classesDefineInFile = []; protected array $classesDefineInFile = [];
/**
* @var array<string, InterfaceDef>
*/
protected array $interfacesDefineInFile = [];
/**
* @var array<string>
*/
protected array $classCeList = [];
protected array $classCeInfo = [];
protected FunctionDef $functionDef; protected FunctionDef $functionDef;
protected ClassDef $classDef; protected ClassDef $classDef;
protected InterfaceDef $interfaceDef;
protected array $globalVars = [ protected array $globalVars = [
'_GET' => self::TYPE_ARRAY, '_GET' => self::TYPE_ARRAY,
'_POST' => self::TYPE_ARRAY, '_POST' => self::TYPE_ARRAY,
@ -203,6 +214,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->indentLevel = 0; $this->indentLevel = 0;
$this->strictTypes = false; $this->strictTypes = false;
$this->classesDefineInFile = []; $this->classesDefineInFile = [];
$this->interfaceDefineInFile = [];
} }
protected function resetNamespace(): void protected function resetNamespace(): void

@ -2,6 +2,7 @@
namespace PhpAot\Php; namespace PhpAot\Php;
use MJS\TopSort\Implementations\StringSort;
use PhpParser\Modifiers; use PhpParser\Modifiers;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\NodeTraverser; use PhpParser\NodeTraverser;
@ -131,25 +132,33 @@ class Translator extends Preprocessor
return self::PREFIX . 'register_class_' . $name; return self::PREFIX . 'register_class_' . $name;
} }
protected function getRegisterClassFunctionCeList(ClassDef $classDef): array protected function getRegisterClassFunctionCeList(ClassDef|InterfaceDef $classDef): array
{ {
$list = []; $list = [];
$parentCe = $this->getParentClassCe($classDef); $parentCe = $this->getParentClassCe($classDef);
$implements = $this->getImplementCe($classDef); if ($parentCe !== '') {
if ($parentCe) {
$list = [$parentCe]; $list = [$parentCe];
} }
// interface 没有 implements
if ($classDef instanceof InterfaceDef) {
return $list;
}
$implements = $this->getImplementCe($classDef);
return array_merge($list, $implements); return array_merge($list, $implements);
} }
public function getRegisterClassFunctionArgs(ClassDef $classDef): string public function getRegisterClassFunctionArgs(ClassDef|InterfaceDef $classDef): string
{ {
return implode(', ', $this->getRegisterClassFunctionCeList($classDef)); return implode(', ', $this->getRegisterClassFunctionCeList($classDef));
} }
private function getRegisterClassFunctionArgDef(ClassDef $classDef): string private function getRegisterClassFunctionArgDef(ClassDef|InterfaceDef $classDef): string
{ {
return 'zend_class_entry *' . implode(', zend_class_entry *', $this->getRegisterClassFunctionCeList($classDef)); $depsCeList = $this->getRegisterClassFunctionCeList($classDef);
if (empty($depsCeList)) {
return '';
}
return 'zend_class_entry *' . implode(', zend_class_entry *', $depsCeList);
} }
protected function getClassCe(ClassLikeDef $classDef): string protected function getClassCe(ClassLikeDef $classDef): string
@ -157,7 +166,7 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName(); return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
} }
protected function getParentClassCe(ClassDef $classDef): string protected function getParentClassCe(ClassLikeDef $classDef): string
{ {
if (!$classDef->extends) { if (!$classDef->extends) {
return ''; return '';
@ -165,7 +174,7 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->extends; return self::PREFIX . 'class_entry_' . $classDef->extends;
} }
private function getImplementCe(ClassLikeDef $classDef): array private function getImplementCe(ClassDef $classDef): array
{ {
return array_map(fn($v) => self::PREFIX . 'class_entry_' . $v, $classDef->implements); return array_map(fn($v) => self::PREFIX . 'class_entry_' . $v, $classDef->implements);
} }
@ -217,6 +226,10 @@ class Translator extends Preprocessor
$cppCode .= $this->genClassWrapper($classDef); $cppCode .= $this->genClassWrapper($classDef);
} }
foreach ($this->interfacesDefineInFile as $interfaceDef) {
$cppCode .= $this->genClassWrapper($interfaceDef);
}
return $this->genIncludeHeaderFiles() . $cppCode; return $this->genIncludeHeaderFiles() . $cppCode;
} }
@ -265,9 +278,45 @@ class Translator extends Preprocessor
return ob_get_clean(); return ob_get_clean();
} }
protected function genClassCeList(): void
{
$sorter = new StringSort();
foreach ($this->interfacesDefineInFile as $interfaceDef) {
$ce = $this->getClassCe($interfaceDef);
$parentCe = $this->getParentClassCe($interfaceDef);
$deps = [];
if ($parentCe !== '') {
$deps[] = $parentCe;
}
$this->classCeInfo[$ce] = [
'deps' => $deps,
'func' => $this->getRegisterClassFunction($interfaceDef->getNamespacedName()),
'args' => $this->getRegisterClassFunctionArgs($interfaceDef),
'argDef' => $this->getRegisterClassFunctionArgDef($interfaceDef),
];
$sorter->add($ce, $deps);
}
foreach ($this->classesDefineInFile as $classDef) {
$ce = $this->getClassCe($classDef);
$depsCeList = $this->getRegisterClassFunctionCeList($classDef);
$this->classCeInfo[$ce] = [
'deps' => $depsCeList,
'func' => $this->getRegisterClassFunction($classDef->getNamespacedName()),
'args' => $this->getRegisterClassFunctionArgs($classDef),
'argDef' => $this->getRegisterClassFunctionArgDef($classDef),
];
$sorter->add($ce, $depsCeList);
}
$this->classCeList = $sorter->sort();
}
public function genExtension(string $file): void public function genExtension(string $file): void
{ {
$this->localHeaders = []; $this->localHeaders = [];
$this->genClassCeList();
$code = $this->render('extension.cc.php'); $code = $this->render('extension.cc.php');
$this->writeFile($file, $code); $this->writeFile($file, $code);
$this->formatCppCode($file); $this->formatCppCode($file);
@ -342,7 +391,7 @@ class Translator extends Preprocessor
protected function getMethodName(Node\Stmt\ClassMethod $v): string protected function getMethodName(Node\Stmt\ClassMethod $v): string
{ {
return strtolower($this->parseIdentifier($v->name)); return $this->parseIdentifier($v->name);
} }
protected function getNativeMethodName(ClassDef $classDef, MethodDef $methodDef): string protected function getNativeMethodName(ClassDef $classDef, MethodDef $methodDef): string
@ -498,7 +547,7 @@ class Translator extends Preprocessor
} }
protected function genClassWrapper(ClassDef $classDef): string protected function genClassWrapper(ClassDef|InterfaceDef $classDef): string
{ {
$cppCode = ''; $cppCode = '';
$name = $classDef->getNamespacedName(); $name = $classDef->getNamespacedName();
@ -508,10 +557,13 @@ class Translator extends Preprocessor
$cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL; $cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL;
$cppCode .= '}' . PHP_EOL . PHP_EOL; $cppCode .= '}' . PHP_EOL . PHP_EOL;
if ($classDef instanceof ClassDef) {
$methods = $classDef->methods; $methods = $classDef->methods;
foreach ($methods as $methodDef) { foreach ($methods as $methodDef) {
$cppCode .= $this->genMethodWrapper($classDef, $methodDef); $cppCode .= $this->genMethodWrapper($classDef, $methodDef);
} }
}
return $cppCode; return $cppCode;
} }
@ -705,9 +757,12 @@ class Translator extends Preprocessor
return $list; return $list;
} }
private function parseInterface(Node $v): void private function parseInterface(Node\Stmt\Interface_ $v): void
{ {
$name = $this->parseIdentifier($v->name); $name = $this->parseIdentifier($v->name);
$this->interfaces[$name] = new InterfaceDef($name, $this->namespace); $this->interface = $name;
$this->interfaceDef = new InterfaceDef($name, $this->namespace);
$this->interfaces[$name] = $this->interfaceDef;
$this->interfacesDefineInFile[$this->interface] = $this->interfaceDef;
} }
} }

@ -14,20 +14,13 @@ foreach ($this->globalVars as $name => $type):
<?= Translator::TYPE_VAR ?> <?= $name ?>; <?= Translator::TYPE_VAR ?> <?= $name ?>;
<?php endforeach; ?> <?php endforeach; ?>
// class entries
<?php
foreach ($this->classes as $classDef) :
?>
zend_class_entry * <?= $this->getClassCe($classDef) ?>;
<?php endforeach; ?>
// class register functions // class register functions
<?php <?php
foreach ($this->classes as $classDef): foreach ($this->classCeList as $ce):
$name = $classDef->getNamespacedName(); $info = $this->classCeInfo[$ce];
$argDef = $this->getRegisterClassFunctionArgDef($classDef);
?> ?>
extern zend_class_entry *<?= $this->getRegisterClassFunction($name) ?>(<?= $argDef ?>); zend_class_entry * <?= $ce ?>;
extern zend_class_entry *<?= $info['func'] ?>(<?= $info['argDef'] ?>);
<?php endforeach; ?> <?php endforeach; ?>
// literal strings // literal strings
@ -59,23 +52,12 @@ static const zend_function_entry ext_functions[] = {
}; };
static PHP_MINIT_FUNCTION(app) { static PHP_MINIT_FUNCTION(app) {
// class // class/interface class entries
<?php
foreach ($this->classes as $classDef):
$name = $classDef->getNamespacedName();
$params = $this->getRegisterClassFunctionArgs($classDef);
$fn = $this->getRegisterClassFunction($name);
?>
<?=$this->getClassCe($classDef)?> = <?= $fn ?>(<?= $params ?>);
<?php endforeach; ?>
<?php <?php
foreach ($this->interfaces as $interfaceDef): foreach ($this->classCeList as $ce):
$name = $interfaceDef->name; $info = $this->classCeInfo[$ce];
$fn = $this->getRegisterClassFunction($name);
?> ?>
<?=$this->getClassCe($interfaceDef)?> = <?= $fn ?>(); <?=$ce?> = <?= $info['func'] ?>(<?= $info['args'] ?>);
<?php endforeach; ?> <?php endforeach; ?>
return SUCCESS; return SUCCESS;

Loading…
Cancel
Save