feat(php): 添加匿名类支持和常量数据处理功能

- 添加 ANON_CLASS 常量用于生成匿名类名称
- 添加 constData 数组用于存储常量数据
- 实现 genAnonClassName 方法生成唯一匿名类名
- 修复 Stmt_Class 处理中的 break 语句缺失问题
- 扩展 parsePostOp 方法支持数组维度获取并检查未定义变量
- 实现 packData 和 addConstData 方法处理字节数据打包
- 在 parseNew 方法中实现对匿名类的完整支持
- 在生成的 C++ 代码中添加常量数据段输出
pull/1/head
韩天峰 7 months ago
parent aa6be88c6c
commit 8ec0723ed5
  1. 52
      src/Php/CompilerBase.php
  2. 8
      src/Php/Translator.php

@ -62,6 +62,7 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string NAMESPACE_SEPARATOR = '__';
public const string PREFIX = 'php_';
public const string ANON_CLASS = '_anon_class_';
public const string OP_ISSET = 'isset';
public const string OP_EMPTY = 'empty';
public const string OP_NOP = "if (0) {}\n";
@ -105,6 +106,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $functionDeclInFile = [];
protected array $functionCallInFile = [];
protected array $redoAfterDeclare = [];
protected array $constData = [];
protected int $optimizeLevel = 0;
protected string $buildMode = 'bin';
protected string $cxxflags = '';
@ -481,6 +483,11 @@ class CompilerBase extends \PhpAot\Core\Translator
return 'tmp_var_' . $this->tmpVarIndex++;
}
public function genAnonClassName(): string
{
return self::ANON_CLASS . $this->tmpVarIndex++;
}
public function writeFile(string $file, string $content): void
{
$dir = dirname($file);
@ -964,7 +971,7 @@ class CompilerBase extends \PhpAot\Core\Translator
break;
case 'Stmt_Class':
$this->fatalError($v, 'Cannot declare class in function');
// no break
break;
default:
abort($v);
}
@ -2001,8 +2008,12 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parsePostOp($expr, string $op): string
{
if ($this->isVarExpr($expr->var) or $this->isPropertyFetch($expr->var)) {
return $this->parseIdentifier($expr->var) . str_repeat($op, 2);
if ($this->isVarExpr($expr->var) or $this->isPropertyFetch($expr->var) or $this->isArrayDimFetch($expr->var)) {
$var = $this->parseIdentifier($expr->var);
if ($this->isVarExpr($expr->var) and !$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->var);
}
return $var . str_repeat($op, 2);
}
if ($this->isStaticPropertyFetch($expr->var)) {
$native = $this->parseNativeStaticPropertyFetch($expr->var);
@ -2334,9 +2345,42 @@ class CompilerBase extends \PhpAot\Core\Translator
return '!(' . $this->parseBinaryOpIdentical($expr) . ')';
}
protected function packData(string $bytes): string
{
$out = '';
for ($i = 0; $i < strlen($bytes); $i++) {
$out .= ord($bytes[$i]) . ', ';
if ($i % 32 == 0) {
$out .= "\n\t";
}
}
return $out;
}
protected function addConstData(string $name, string $bytes): void
{
$this->constData[$name] = $this->packData($bytes);
}
protected function parseNew(Node\Expr\New_ $expr): string
{
$className = $this->parseIdentifier($expr->class);
// 匿名类
if ($expr->class instanceof Node\Stmt\Class_) {
if ($expr->class->name === null) {
$classDef = $expr->class;
$className = $this->genAnonClassName();
$classDef->name = new Node\Identifier($className);
$this->beforeStmtLines[] = 'static THREAD_LOCAL bool ' . $className . '_defined = false;';
$classCode = $this->genEmbeddedCode($classDef);
$this->addConstData($className . '_code', $classCode);
$this->beforeStmtLines[] = 'if (!' . $className . '_defined) {'
. $className . '_defined = true; php::eval((const char *)' . $className . '_code);}';
} else {
$this->fatalError($expr, 'must be anonymous class');
}
} else {
$className = $this->parseIdentifier($expr->class);
}
$className = $this->getNamespacedClassName($className);
$args = $expr->args;
$cePtr = $this->getClassEntryPtr($className);

@ -513,7 +513,13 @@ class Translator extends Preprocessor
$cppCode .= $this->genFunctionWrapper($functionDef);
}
return $this->genIncludeHeaderFiles() . $cppCode;
$constDataCode = '';
foreach ($this->constData as $name => $data) {
$constDataCode .= 'static const unsigned char ' . $name . '[] = {' . $data . '};' . PHP_EOL;
}
$constDataCode .= PHP_EOL;
return $this->genIncludeHeaderFiles() . $constDataCode . $cppCode;
}
protected function genClassCeList(): void

Loading…
Cancel
Save