refactor(php): 重构PHP到C++编译器实现细节

- 更新PHP CS Fixer配置中的类属性分离规则
- 简化ArgInfo、ClassDef、ClassLikeDef等数据结构定义
- 重命名CLASS_ENTRY_MAP为CLASS_MAP并更新相关引用
- 移除多余变量声明并优化全局变量处理逻辑
- 实现超级全局变量检测和初始化功能
- 添加对$GLOBALS数组访问的支持
- 优化函数调用代码生成逻辑
- 添加全局变量测试用例验证功能
- 清理无用常量和变量声明简化代码结构
pull/1/head
韩天峰 7 months ago
parent 2c90437a99
commit 38110f67d5
  1. 4
      .php-cs-fixer.dist.php
  2. 2
      src/Php/ArgInfo.php
  3. 4
      src/Php/ClassDef.php
  4. 2
      src/Php/ClassLikeDef.php
  5. 112
      src/Php/CompilerBase.php
  6. 3
      src/Php/ConstantDef.php
  7. 7
      src/Php/Encryptor.php
  8. 1
      src/Php/Extractor.php
  9. 2
      src/Php/FileScanner.php
  10. 1
      src/Php/FileSorter.php
  11. 4
      src/Php/FunctionDef.php
  12. 2
      src/Php/MethodDef.php
  13. 3
      src/Php/PropertyDef.php
  14. 14
      src/Php/Translator.php
  15. 13
      src/template/extension.cc.php
  16. 17
      tests/aot/global-vars.phpt

@ -19,7 +19,7 @@ return (new PhpCsFixer\Config())
'binary_operator_spaces' => ['operators' => ['=' => null, '=>' => null, ]],
'blank_line_after_namespace' => true,
'blank_line_before_statement' => ['statements' => ['declare']],
'class_attributes_separation' => true,
'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'only_if_meta']],
'concat_space' => ['spacing' => 'one'],
'constant_case' => ['case' => 'lower'],
'combine_consecutive_unsets' => true,
@ -63,4 +63,4 @@ return (new PhpCsFixer\Config())
->exclude(['html', 'vendor'])
->in(__DIR__)
)
->setUsingCache(false);
->setUsingCache(false);

@ -11,8 +11,6 @@ namespace PhpAot\Php;
class ArgInfo
{
public string $name;
public string $type;
public string $default = '';
}

@ -24,13 +24,9 @@ class ClassDef extends ClassLikeDef
* @var array<string, ConstantDef>
*/
public array $constants = [];
public array $implements = [];
public string $extends = '';
public bool $requireCtor = false;
public int $flags;
public function __construct(string $name, int $flags, string $namespace = '')

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

@ -34,27 +34,16 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string TYPE_INT = 'php::Int';
public const string TYPE_FLOAT = 'php::Float';
public const string TYPE_OBJECT = 'php::Object';
public const string TYPE_ARRAY = 'php::Array';
public const string TYPE_STR = 'php::Str';
public const string TYPE_REF = 'php::Ref';
public const string TYPE_VOID = 'void';
public const string VALUE_NAN = 'std::numeric_limits<double>::quiet_NaN()';
public const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
public const string LITERAL_STRINGS = '_literal_strings';
public const string CLASS_ENTRY_MAP = 'class_entry_map';
public const string CLASS_MAP = 'class_map';
public const string FUNC_MAP = 'func_map';
public const string EXPR_VARIABLE = 'Expr_Variable';
public const string EXPR_NEW = 'Expr_New';
@ -64,32 +53,21 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string NAMESPACE_SEPARATOR = '__';
public const string PREFIX = 'php_';
protected string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP';
protected string $cppCompiler = 'g++';
protected array $arguments = [];
protected array $literalStrings = [];
protected int $literalStringIndex = 0;
protected int $tmpVarIndex = 0;
protected int $classIndex = 0;
/**
* @var array<string, int>
*/
protected array $classMap = [];
protected int $funcIndex = 0;
protected array $funcMap = [];
protected array $zendTypeMap = [
'int' => self::TYPE_INT,
'float' => self::TYPE_FLOAT,
@ -100,7 +78,6 @@ class CompilerBase extends \PhpAot\Core\Translator
'object' => self::TYPE_OBJECT,
'mixed' => self::TYPE_VAR,
];
protected array $globalHeaders = [
'phpx.h',
'phpx_helper.h',
@ -108,68 +85,44 @@ class CompilerBase extends \PhpAot\Core\Translator
'php_func_decl.h',
'php_global_var_decl.h',
];
protected array $localHeaders = [];
protected array $nativeFunctions = [];
protected array $internalFunctions = [];
protected array $nativeConstants = [];
protected array $functionDeclInFile = [];
protected array $functionCallInFile = [];
protected array $redoAfterDeclare = [];
protected int $optimizeLevel = 0;
protected string $buildMode = 'bin';
protected string $cxxflags = '';
protected string $ldflags = '';
protected int $floatPrecision = 17;
protected bool $debugInfo = true;
protected bool $noLiteralStrings = false;
protected bool $useCppNamespace = false;
protected string $file;
protected string $dir;
/**
* 原始值,可能包含 `\\` 多层空间.
*/
protected string $namespace = '';
protected string $method = '';
protected string $function = '';
protected array $useNamespaces = [];
protected array $useAliases = [];
protected array $useFunctions = [];
/**
* 原始类名,不包含命名空间.
*/
protected string $class = '';
protected string $interface = '';
/**
* @var array<string, ClassDef>
*/
protected array $classes = [];
protected array $interfaces = [];
/**
@ -196,16 +149,11 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string>
*/
protected array $classCeList = [];
protected array $classCeInfo = [];
protected FunctionDef $functionDef;
protected ClassDef $classDef;
protected InterfaceDef $interfaceDef;
protected array $globalVars = [
protected array $superGlobalVars = [
'_GET' => self::TYPE_ARRAY,
'_POST' => self::TYPE_ARRAY,
'_COOKIE' => self::TYPE_ARRAY,
@ -213,45 +161,30 @@ class CompilerBase extends \PhpAot\Core\Translator
'_FILES' => self::TYPE_ARRAY,
'_SESSION' => self::TYPE_ARRAY,
'_REQUEST' => self::TYPE_ARRAY,
'GLOBALS' => self::TYPE_ARRAY,
'argc' => self::TYPE_INT,
'argv' => self::TYPE_ARRAY,
];
protected array $globalVars = [];
/**
* @var array<string, string>
*/
protected array $objects = [];
protected array $localVars = [];
protected array $objectWrappers = [];
protected bool $strictTypes = false;
protected string $rootPath;
protected string $buildDir;
protected int $debugLine = 0;
protected CLImate $climate;
protected array $beforeStmtLines = [];
protected array $afterStmtLines = [];
protected bool $inLoop = false;
/**
* 赋值表达式的左值,写操作,右值为读操作.
*/
protected bool $inAssignExpr = false;
protected bool $stubFile = false;
protected bool $enableProfiler = false;
protected Parser $parser;
public function __construct(string $rootPath)
@ -301,6 +234,14 @@ class CompilerBase extends \PhpAot\Core\Translator
return isset($this->objects[$object]);
}
protected function isSuperGlobal(string $var): bool
{
if (isset($this->superGlobalVars[$var])) {
return true;
}
return false;
}
public function parseExpr(mixed $expr)
{
$type = $expr->getType();
@ -669,7 +610,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->classMap[$className] = $id;
}
return 'php_get_class_entry(' . $id . ', "' . $this->escapeString($className) . '")';
return 'php_get_class(' . $id . ', "' . $this->escapeString($className) . '")';
}
protected function getFuncPtr(string $funcName): string
@ -677,11 +618,10 @@ class CompilerBase extends \PhpAot\Core\Translator
if (isset($this->funcMap[$funcName])) {
$id = $this->funcMap[$funcName];
} else {
$id = $this->funcIndex++;
$id = $this->funcIndex++;
$this->funcMap[$funcName] = $id;
}
return 'php_get_func(' . $id . ', "' . $this->escapeString($funcName) . '")';
return $id . ', "' . $this->escapeString($funcName) . '"';
}
protected function parseFunctionDeclaration(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): FunctionDef
@ -800,7 +740,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if (is_object($expr->name) and $this->isVarExpr($expr->name)) {
$this->fatalError($expr, 'The `$$` syntax is not supported');
}
if ($this->isSuperGlobal($expr->name) and !$this->hasGlobalVar($expr->name)) {
$this->addGlobalVar($expr->name, $this->superGlobalVars[$expr->name]);
}
return $this->escapeVarName($expr->name);
case 'Name':
case 'VarLikeIdentifier':
@ -1710,9 +1652,15 @@ class CompilerBase extends \PhpAot\Core\Translator
}
}
protected function parseArrayDimFetch($node, bool $write): string
protected function parseArrayDimFetch(Node\Expr\ArrayDimFetch $node, bool $write): string
{
$var = $this->parseIdentifier($node->var);
if ($this->isVarExpr($node->var) and $var === 'GLOBALS') {
if ($node->dim === null) {
$this->fatalError($node, 'Cannot use [] for GLOBALS');
}
return 'php::global(' . $this->parseIdentifier($node->dim) . ')';
}
if ($node->dim === null) {
if (!$write) {
$this->fatalError($node, 'Cannot use [] for reading');
@ -1781,6 +1729,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseFuncCall(Node\Expr\FuncCall $expr, bool $silent = false): string
{
$call = '';
if ($this->isVarExpr($expr->name)) {
$fn = $this->parseIdentifier($expr->name);
$name = '';
@ -1798,6 +1747,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return $code;
}
$fn = $this->getFuncPtr($name);
$call = $silent ? 'CALL_SILENT' : 'CALL';
} else {
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_VAR);
@ -1805,8 +1755,9 @@ class CompilerBase extends \PhpAot\Core\Translator
$fn = $tmpVar;
$name = '';
}
$call = $silent ? 'php::silentCall' : 'php::call';
if (!$call) {
$call = $silent ? 'php::silentCall' : 'php::call';
}
if (empty($expr->args)) {
return $call . '(' . $fn . ')';
}
@ -2307,6 +2258,11 @@ class CompilerBase extends \PhpAot\Core\Translator
return strtolower($class);
}
protected function escapeFileName(string $file): string
{
return str_replace('-', '_', $file);
}
protected function unescapeVarName(string $name): string
{
return str_replace('_php__var__', '', $name);

@ -11,11 +11,8 @@ namespace PhpAot\Php;
class ConstantDef
{
public string $name;
public string $type;
public string $flags;
public string $value;
public function __construct(string $name, string $flags, string $type, string $value)

@ -13,21 +13,14 @@ use PhpParser\PrettyPrinter\Standard;
class Encryptor extends \PhpAot\Core\Translator
{
protected array $stmts;
protected string $phpxDir = '~/workspace/phpx';
protected string $lang = 'PHP';
protected array $typeMap = [];
protected array $headers = [
'phpx.h',
];
protected array $encodeMap;
protected array $decodeMap;
protected array $constants;
public function __construct(array $stmts)

@ -11,7 +11,6 @@ namespace PhpAot\Php;
class Extractor
{
private string $ctagsPath = 'ctags';
private bool $isUniversalCtags = false;
public function __construct()

@ -13,9 +13,7 @@ class FileScanner
public const array PHP_EXT = ['php'];
public const array CPP_EXT = ['cpp', 'cxx', 'cc'];
private string $directory;
private array $excludePatterns;
public function __construct(string $directory)

@ -11,7 +11,6 @@ namespace PhpAot\Php;
class FileSorter
{
private array $functionDeclInFile;
private array $functionCallInFile;
public function __construct(array $functionDeclInFile, array $functionCallInFile)

@ -11,18 +11,14 @@ namespace PhpAot\Php;
class FunctionDef
{
public string $name;
public string $returnType;
/**
* @var array<ArgInfo>
*/
public array $argInfoList = [];
public int $argCountRequired = 0;
public string $params = '';
public bool $method = false;
public function __construct(string $name, string $returnType)

@ -11,9 +11,7 @@ namespace PhpAot\Php;
class MethodDef
{
public int $flags;
public string $name;
public FunctionDef $functionDef;
public function __construct(int $flags, string $name, FunctionDef $def)

@ -13,11 +13,8 @@ use PhpParser\Modifiers;
class PropertyDef
{
public string $name;
public string $type;
public int $flags;
public ?string $default = null;
public function __construct(string $name, int $flags, string $type, ?string $default = null)

@ -18,15 +18,10 @@ use Symfony\Component\Yaml\Yaml;
class Translator extends Preprocessor
{
use MagicMethodDetector;
protected string $targetName = 'app';
protected bool $verbose = false;
protected array $phpSrcFiles = [];
protected array $argInfoHeaderFiles = [];
protected array $unsupportedFunctions = [
'compact',
'extract',
@ -204,8 +199,8 @@ class Translator extends Preprocessor
$literalStringsCount = count($this->literalStrings);
$lines[] = 'extern php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
$classEntryCount = count($this->classMap);
$lines[] = 'extern zend_class_entry *' . self::PREFIX . self::CLASS_ENTRY_MAP . '[' . $classEntryCount . '];' . PHP_EOL;
$classCount = count($this->classMap);
$lines[] = 'extern zend_class_entry *' . self::PREFIX . self::CLASS_MAP . '[' . $classCount . '];' . PHP_EOL;
$funcCount = count($this->funcMap);
$lines[] = 'extern zend_function *' . self::PREFIX . self::FUNC_MAP . '[' . $funcCount . '];' . PHP_EOL;
@ -300,8 +295,10 @@ class Translator extends Preprocessor
$code .= 'extern ' . $constant->type . ' ' . $name . ';' . PHP_EOL;
}
$code .= 'extern zend_class_entry *php_get_class_entry(int class_id, const char *class_name);' . PHP_EOL;
$code .= 'extern zend_class_entry *php_get_class(int class_id, const char *class_name);' . PHP_EOL;
$code .= 'extern zend_function *php_get_func(int func_id, const char *func_name);' . PHP_EOL;
$code .= '#define CALL(id, name, args) php::call(php_get_func(id, name), args)' . PHP_EOL;
$code .= '#define CALL_SILENT(id, name, args) php::silentCall(php_get_func(id, name), args)' . PHP_EOL;
$this->writeFile($file, $code);
}
@ -314,6 +311,7 @@ class Translator extends Preprocessor
public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string
{
$basename = self::PREFIX . basename($stubFilenameWithoutExtension);
$basename = $this->escapeFileName($basename);
$absPath = $this->getIncludeDir() . "/{$basename}_arginfo.h";
if ($relative) {
return ltrim($this->removeCommonPrefix($this->getIncludeDir(), $absPath), '/');

@ -22,16 +22,16 @@ zend_class_entry * <?= $ce ?>;
<?php endforeach; ?>
// class entry
zend_class_entry *<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP . '[' . count($this->classMap) . ']' ?>;
zend_class_entry *<?= Translator::PREFIX . Translator::CLASS_MAP . '[' . count($this->classMap) . ']' ?>;
// func
zend_function *<?= Translator::PREFIX . Translator::FUNC_MAP . '[' . count($this->funcMap) . ']' ?>;
zend_class_entry *php_get_class_entry(int class_id, const char *class_name) {
if (UNEXPECTED(<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id] == nullptr)) {
<?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id] = php::getClassEntrySafe(class_name);
zend_class_entry *php_get_class(int class_id, const char *class_name) {
if (UNEXPECTED(<?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] == nullptr)) {
<?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id] = php::getClassEntrySafe(class_name);
}
return <?= Translator::PREFIX . Translator::CLASS_ENTRY_MAP ?>[class_id];
return <?= Translator::PREFIX . Translator::CLASS_MAP ?>[class_id];
}
zend_function *php_get_func(int func_id, const char *func_name) {
@ -104,7 +104,7 @@ foreach ($this->nativeConstants as $name => $constant):
<?php
foreach ($this->globalVars as $name => $type):
?>
<?= $name ?> = php::global("<?=$name?>");
php::initGlobal("<?=$name?>", <?= $name ?>);
<?php endforeach; ?>
// property offset
@ -124,6 +124,7 @@ void php_app_clean() {
foreach ($this->globalVars as $name => $type) :
?>
<?= $name ?>.unset();
php::unsetGlobal("<?=$name?>");
<?php endforeach; ?>
<?php
foreach ($this->nativeConstants as $name => $constant):

@ -0,0 +1,17 @@
--TEST--
global vars
--FILE--
<?php
global $a;
$a = 100;
var_dump($GLOBALS['a']);
var_dump($a);
var_dump(gettype($_SERVER));
var_dump($_SERVER['argc']);
?>
--EXPECTF--
int(100)
int(100)
string(5) "array"
int(%d)
Loading…
Cancel
Save