fix(generator): 修复闭包生成器中的变量状态恢复问题

- 将闭包生成器中的变量状态恢复代码从条件判断前移到条件判断后
- 确保在不使用当前作用域时正确恢复原始局部变量状态
- 统一对象、对象包装器、参数和闭包状态的恢复逻辑位置

refactor(compiler): 重构编译器基类中的函数和类管理逻辑

- 添加对函数定义存储结构的注释说明
- 移除废弃的 isNativeFunction 方法
- 添加 inClosure 状态重置功能
- 优化命名空间类名获取逻辑,移除冗余反斜杠
- 修复类方法不应保存到函数集合中的问题
- 添加函数添加辅助方法和原生函数检查方法
- 更新函数调用返回类型检测逻辑

feat(translator): 增强翻译器对类和接口的支持

- 添加对PHP属性声明的支持
- 增加对类常量重复定义的错误检查
- 完善接口解析和实现逻辑
- 优化类定义和继承关系处理
- 改进类常量和属性定义的解析方式

style(helper): 更新C++辅助头文件依赖

- 添加对Zend属性的支持
- 统一代码格式化和命名约定

perf(core): 优化对象克隆和类型转换性能

- 使用 convertToObject 方法替代直接标识符解析
- 提升实例化检查和类型转换效率
- 改进属性访问和错误报告机制
pull/1/head
韩天峰 6 months ago
parent 989939bb90
commit dac3fa81e8
  1. 84
      src/Php/CompilerBase.php
  2. 16
      src/Php/Generator/ClosureGenerator.php
  3. 14
      src/Php/Generator/Utils.php
  4. 34
      src/Php/Translator.php
  5. 2
      src/cpp/php_aot_helper.h

@ -112,6 +112,10 @@ class CompilerBase extends \PhpAot\Core\Translator
'php_aot_helper.h',
];
protected array $localHeaders = [];
/**
* 存储所有函数、类方法的定义,key 是 native name,命名空间需要转为 `_`,并且必须为小写
* @var array<string, FunctionDef>
*/
protected array $nativeFunctions = [];
protected array $internalFunctions = [];
protected array $nativeConstants = [];
@ -150,6 +154,9 @@ class CompilerBase extends \PhpAot\Core\Translator
* @var array<string, ClassDef>
*/
protected array $classes = [];
/**
* @var array<string, InterfaceDef>
*/
protected array $interfaces = [];
/**
@ -255,11 +262,6 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->zendTypeMap[$type] ?? self::TYPE_VAR;
}
public function isNativeFunction(string $name): bool
{
return isset($this->nativeFunctions[$name]);
}
public function isTypedObject(string $object): bool
{
return isset($this->objects[$object]);
@ -544,6 +546,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->inLoop = false;
$this->function = '';
$this->functionDef = null;
$this->inClosure = false;
}
protected function resetMethod(): void
@ -603,7 +606,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function getNamespacedClassName(string $class): string
{
if ($class[0] === '\\') {
return $class;
return ltrim($class, '\\');
}
$ns2 = explode('\\', trim($class, '\\'));
@ -614,8 +617,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if (count($ns2) > 1) {
$ns .= '\\' . implode('\\', array_slice($ns2, 1));
}
return $ns;
return ltrim($ns, '\\');
}
foreach ($this->useNamespaces as $useNamespace) {
@ -628,10 +630,10 @@ class CompilerBase extends \PhpAot\Core\Translator
$currentNamespace = $this->namespace;
if (!empty($currentNamespace)) {
return '\\' . trim($currentNamespace, '\\') . '\\' . $class;
return trim($currentNamespace, '\\') . '\\' . $class;
}
return '\\' . $class;
return $class;
}
protected function getPropertyOffset(string $property, string $class, string $namespace = ''): string
@ -747,7 +749,7 @@ class CompilerBase extends \PhpAot\Core\Translator
{
$this->resetFunction();
$this->function = $this->parseIdentifier($v->name);
$name = $this->getFunctionName($v);
$name = $this->getFunctionName($v);
if (isset($this->nativeFunctions[$name])) {
$this->functionDef = $this->nativeFunctions[$name];
} else {
@ -759,6 +761,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
}
// 类方法不要保存到 functions 中
if ($this->class) {
$this->addArgument('this_', self::TYPE_OBJECT);
if ($this->methodDef) {
@ -766,7 +769,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->methodDef->functionDef = $this->functionDef;
}
} else {
$this->functions[$name] = $this->functionDef;
$this->functions[$name] = $this->functionDef;
$this->functionDefineInFile[$name] = $this->functionDef;
}
@ -923,7 +926,8 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->fatalError($param, 'Promoted properties are not supported');
}
$name = $this->parseIdentifier($param->var);
$propertyDef = new PropertyDef($name, $param->flags, $param->type, $this->parseParamDefaultValue($param->default));
$type = $param->type === null ? '' : $param->type;
$propertyDef = new PropertyDef($name, $param->flags, $type, $this->parseParamDefaultValue($param->default));
$this->classDef->properties[$name] = $propertyDef;
}
if ($param->variadic and $i !== $last) {
@ -1427,6 +1431,11 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->classes[$this->escapeClass($name)] = $classDef;
}
protected function addFunction(string $name, FunctionDef $functionDef): void
{
$this->functions[$this->escapeFunction($name)] = $functionDef;
}
protected function hasVar(string $name): bool
{
return $this->hasLocalVar($name) || $this->hasGlobalVar($name) || $this->hasStaticVar($name);
@ -1437,11 +1446,24 @@ class CompilerBase extends \PhpAot\Core\Translator
return isset($this->localVars[$name]);
}
/**
* @param string $name 必须传入带有完整命名空间的类名,将会自动转义为 native name
* @return bool
*/
protected function hasNativeClass(string $name): bool
{
return array_key_exists($this->escapeClass($name), $this->classes);
}
/**
* @param string $name 必须传入带有完整命名空间的类名,将会自动转义为 native name
* @return bool
*/
protected function hasNativeFunction(string $name): bool
{
return array_key_exists($this->escapeFunction($name), $this->nativeFunctions);
}
protected function getNativeStaticMethod(string $class, string $method): string|false
{
if (!$this->hasNativeClass($class)) {
@ -1513,8 +1535,8 @@ class CompilerBase extends \PhpAot\Core\Translator
break;
case 'Expr_FuncCall':
$name = $this->parseIdentifier($expr->name);
if ($this->isNativeFunction($name)) {
return $this->nativeFunctions[$name]->returnType;
if ($this->hasNativeFunction($name)) {
return $this->functions[$name]->returnType;
}
return $this->detectFuncCallReturnType($name);
case 'Expr_New':
@ -2038,11 +2060,11 @@ class CompilerBase extends \PhpAot\Core\Translator
// 跳过,稍后再处理
if (isset($this->functionDeclInFile[$name])
and $this->functionDeclInFile[$name] === $this->file
and !$this->isNativeFunction($name)) {
and !$this->hasNativeFunction($name)) {
$this->redoAfterDeclare[$name] = true;
throw new Skip();
}
if ($this->isNativeFunction($name)) {
if ($this->hasNativeFunction($name)) {
return $name;
}
}
@ -2163,6 +2185,10 @@ class CompilerBase extends \PhpAot\Core\Translator
// 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用
$this->addLocalVar($name, self::TYPE_REF);
} else {
// 本地变量,且是原生类型,则转为普通变量
if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) {
$this->localVars[$name] = self::TYPE_VAR;
}
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
$tmpVar = $this->genTmpVarName();
$this->addLocalVar($tmpVar, self::TYPE_REF);
@ -2612,16 +2638,12 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseClone(Node\Expr\Clone_ $expr): string
{
$var = $this->parseIdentifier($expr->expr);
return $var . '.clone()';
return $this->convertToObject($expr->expr) . '.clone()';
}
protected function parseInstanceof(Node\Expr\Instanceof_ $expr): string
{
$var = $this->parseIdentifier($expr->expr);
return $var . '.instanceOf(' . $this->identifierToStr($expr->class) . ')';
return $this->convertToObject($expr->expr) . '.instanceOf(' . $this->identifierToStr($expr->class) . ')';
}
protected function parseCastInt(Node\Expr\Cast\Int_ $node): string
@ -2817,9 +2839,9 @@ class CompilerBase extends \PhpAot\Core\Translator
$propertyName = $this->parseIdentifier($property);
$nativeProperty = null;
if ($objectName === 'this_') {
$nativeProperty = $this->findNativeProperty($propertyName, $this->class, $this->namespace);
$nativeProperty = $this->findNativeProperty($object, $propertyName, $this->class, $this->namespace);
} elseif ($this->isTypedObject($objectName)) {
$nativeProperty = $this->findNativeProperty($propertyName, $this->objects[$objectName]);
$nativeProperty = $this->findNativeProperty($object, $propertyName, $this->objects[$objectName]);
}
if ($nativeProperty) {
return $nativeProperty;
@ -3435,7 +3457,7 @@ class CompilerBase extends \PhpAot\Core\Translator
return null;
}
protected function findNativeProperty($property, string $class, string $namespace = ''): ?string
protected function findNativeProperty(NodeAbstract $object, string $property, string $class, string $namespace = ''): ?string
{
$findClass = $class;
if ($namespace) {
@ -3455,18 +3477,18 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($scope) {
return self::PREFIX . $this->getPropertyOffset($property, $classDef->name, $classDef->namespace);
}
$this->fatalError($property, "Cannot access protected property `{$property}` of class `{$class}`");
$this->fatalError($object, "Cannot access protected property `{$property}` of class `{$class}`");
} else {
if ($scope === $findClass) {
return self::PREFIX . $this->getPropertyOffset($property, $classDef->name, $classDef->namespace);
}
$this->error("Cannot access private property `{$property}` of class `{$class}`");
$this->fatalError($object, "Cannot access private property `{$property}` of class `{$class}`");
}
} elseif ($classDef->extends) {
$findClass = $classDef->namespace . '\\' . $classDef->extends;
$findClass = $classDef->extends;
continue;
} else {
$this->error("Property `{$property}` does not exist in class `{$class}`");
$this->fatalError($object, "Property `{$property}` does not exist in class `{$class}`");
}
}
break;
@ -3799,7 +3821,7 @@ class CompilerBase extends \PhpAot\Core\Translator
}
$nativeFunc = $this->getNativeName($method, $classDef->namespace, $classDef->name);
}
if ($nativeFunc and $this->isNativeFunction($nativeFunc)) {
if ($nativeFunc and $this->hasNativeFunction($nativeFunc)) {
return $nativeFunc;
}
return false;

@ -69,14 +69,6 @@ trait ClosureGenerator
$code .= '};' . PHP_EOL;
$this->beforeStmtLines[] = $code;
if (!$useCurrentScope) {
$this->localVars = $oriLocalVars;
}
$this->objects = $oriObjects;
$this->objectWrappers = $oriObjectWrappers;
$this->arguments = $oriArgs;
$this->inClosure = $oriInClosure;
$useVars = [];
if ($uses) {
@ -93,6 +85,14 @@ trait ClosureGenerator
}
}
if (!$useCurrentScope) {
$this->localVars = $oriLocalVars;
}
$this->objects = $oriObjects;
$this->objectWrappers = $oriObjectWrappers;
$this->arguments = $oriArgs;
$this->inClosure = $oriInClosure;
if ($this->methodDef) {
return 'php::newClosure(' . $tmpVar . ', { ' . implode(', ', $useVars) . ' }, this_)';
} else {

@ -54,9 +54,14 @@ trait Utils
return str_replace('\\', self::NAMESPACE_SEPARATOR, strtolower($ns));
}
protected function escapeZendFnName(string $fn): string
protected function escapeZendFnName(string $fn, bool $lower = true): string
{
return str_replace('\\', '_', strtolower($fn));
return str_replace('\\', '_', $lower ? strtolower($fn) : $fn);
}
protected function escapeCeName(string $name): string
{
return $this->escapeZendFnName($name, false);
}
protected function escapeName(string $name): string
@ -69,6 +74,11 @@ trait Utils
return str_replace('\\', '_', trim(strtolower($class), '\\'));
}
protected function escapeFunction(string $func): string
{
return $this->escapeClass($func);
}
protected function escapeFileName(string $file): string
{
return str_replace('-', '_', $file);

@ -296,9 +296,6 @@ class Translator extends Preprocessor
$literalStringsCount = count($this->literalStrings);
$code .= 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
/**
* @var FunctionDef $func
*/
foreach ($this->nativeFunctions as $name => $func) {
$code .= 'extern ' . $func->returnType . ' ' . self::PREFIX . $name . '(';
$list = [];
@ -307,9 +304,6 @@ class Translator extends Preprocessor
}
$argInfoList = $func->argInfoList;
if ($argInfoList) {
/**
* @var ArgInfo $argInfo
*/
foreach ($argInfoList as $argInfo) {
if ($argInfo->variadic) {
$arg = self::TYPE_ARRAY . ' ' . $argInfo->name . '()';
@ -396,7 +390,7 @@ class Translator extends Preprocessor
protected function getClassCe(ClassLikeDef $classDef): string
{
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
return self::PREFIX . 'class_entry_' . $this->escapeCeName($classDef->getNamespacedName());
}
protected function getFilesFromDir(string $path): array
@ -472,7 +466,7 @@ class Translator extends Preprocessor
return '';
}
return self::PREFIX . 'class_entry_' . $classDef->extends;
return self::PREFIX . 'class_entry_' . $this->escapeCeName($classDef->extends);
}
protected function doConvert(string $phpCode): string
@ -592,7 +586,7 @@ class Translator extends Preprocessor
$implements = $classDef->implements;
if ($implements) {
foreach ($implements as $interface) {
$tmpCe = self::PREFIX . 'class_entry_' . $interface;
$tmpCe = self::PREFIX . 'class_entry_' . $this->escapeCeName($interface);
if (!isset($this->interfaces[$interface])) {
$sorter->add($tmpCe);
}
@ -648,6 +642,7 @@ class Translator extends Preprocessor
$code .= $this->parseUse($v2) . PHP_EOL;
break;
case 'Stmt_Interface':
$code .= $this->parseInterface($v2) . PHP_EOL;
break;
default:
abort($v2);
@ -694,13 +689,20 @@ class Translator extends Preprocessor
$extends = $class->extends;
}
$this->classDef = new ClassDef($this->class, $flags, $this->namespace);
$nativeName = $this->getNativeName('', $this->class, $this->namespace);
if ($this->hasNativeClass($nativeName)) {
$this->classDef = $this->classes[$nativeName];
} else {
$this->classDef = new ClassDef($this->class, $flags, $this->namespace);
$this->addClass($nativeName, $this->classDef);
}
if ($class instanceof Node\Stmt\Enum_) {
$this->classDef->enum = true;
}
if ($extends) {
$this->classDef->extends = $this->parseIdentifier($class->extends);
$this->classDef->extends = $this->getNamespacedClassName($this->parseIdentifier($class->extends));
if (isset($this->classes[$this->classDef->extends])) {
$parent = $this->classes[$this->classDef->extends];
if ($parent->flags & Modifiers::FINAL) {
@ -711,7 +713,6 @@ class Translator extends Preprocessor
$this->classDef->implements = $this->parseIdentifierList($class->implements);
$className = $this->classDef->getNamespacedName();
$this->addClass($className, $this->classDef);
$this->classesDefineInFile[$className] = $this->classDef;
$methodCodes = [];
@ -906,10 +907,7 @@ class Translator extends Preprocessor
$type = $v->type ? $this->getTypeFromZendType($this->parseIdentifier($v->type)) : self::TYPE_VAR;
foreach ($v->consts as $const) {
$constName = $this->parseIdentifier($const->name);
if (isset($this->classDef->constants[$constName])) {
$this->fatalError($const, 'Cannot redefine class constant ' . $this->class . '::' . $constName);
}
$constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value));
$constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value));
$this->classDef->constants[$constInfo->name] = $constInfo;
}
}
@ -954,7 +952,7 @@ class Translator extends Preprocessor
{
$list = [];
foreach ($implements as $implement) {
$list[] = $this->parseIdentifier($implement);
$list[] = $this->getNamespacedClassName($implement);
}
return $list;
@ -1026,7 +1024,7 @@ class Translator extends Preprocessor
{
$list = [];
foreach ($classDef->implements as $interface) {
$list[] = self::PREFIX . 'class_entry_' . $interface;
$list[] = self::PREFIX . 'class_entry_' . $this->escapeCeName($interface);
}
return $list;

@ -1,5 +1,7 @@
#include <phpx.h>
#include <zend_attributes.h>
extern zend_class_entry *php_get_class(int class_id, const php::Str &class_name);
extern zend_function *php_get_func(int func_id, const php::Str &func_name);
extern zend_function *php_get_method(int func_id, const php::Str &method_name, int class_id, const php::Str &class_name);

Loading…
Cancel
Save