feat(enum): 支持枚举类型解析和处理

- 添加了枚举类型的语法解析功能
- 实现了对带值枚举(backed enums)的支持
- 添加了枚举案例值的存储和访问机制
- 支持枚举类型的运行时对象处理
- 完善了枚举常量数组的生成逻辑
- 新增了多个枚举相关的测试用例
pull/1/head
韩天峰 2 months ago
parent 6849c56cc2
commit 26bdf5eb59
  1. 11
      src/Php/Entity/ClassDef.php
  2. 6
      src/Php/Preprocessor.php
  3. 11
      src/Php/Translator.php
  4. 41
      tests/aot/enum/3.phpt
  5. 30
      tests/aot/enum/4.phpt
  6. 31
      tests/aot/enum/5.phpt

@ -32,6 +32,17 @@ class ClassDef extends ClassLikeDef
public string $extends = '';
public bool $requireCtor = false;
public bool $enum = false;
/**
* Backing type for backed enums ('int' or 'string'), null for pure enums.
*/
public ?string $enumBackingType = null;
/**
* Enum cases: case name => backing value (int/string for backed enums, null for pure enums).
* @var array<string, int|string|null>
*/
public array $enumCases = [];
public ?Trait_ $trait = null;
/**

@ -438,6 +438,9 @@ class Preprocessor extends CompilerBase
if ($class instanceof Node\Stmt\Enum_) {
$this->classDef->enum = true;
if ($class->scalarType !== null) {
$this->classDef->enumBackingType = $class->scalarType->name;
}
}
if (!$class instanceof Node\Stmt\Trait_) {
$this->classDef->implements = $this->parseImplements($class->implements);
@ -464,7 +467,10 @@ class Preprocessor extends CompilerBase
$this->prepareTraitUse($v);
break;
case 'Stmt_Nop':
break;
case 'Stmt_EnumCase':
$caseName = $this->parseIdentifier($v->name);
$this->classDef->enumCases[$caseName] = $v->expr?->value;
break;
case 'Stmt_ClassMethod':
$this->prepareClassMethod($v, $class);

@ -1518,6 +1518,17 @@ CODE;
return $this->genCValue(constant($constName));
}
}
// Resolve enum case references. Enum cases are runtime objects; their
// actual values in class constant arrays are set at runtime by
// genClassArrayConstants() via php::getEnumCase(). Return the backing
// value as a placeholder so gen_stub.php's ConstExprEvaluator can complete.
if ($this->hasClass($class)) {
$classDef = $this->getClass($class);
if ($classDef->enum && array_key_exists($name, $classDef->enumCases)) {
$caseValue = $classDef->enumCases[$name];
return $this->genCValue($caseValue ?? $name);
}
}
$this->fatalError($expr, "Class constant `{$class}::{$name}` not found");
}

@ -0,0 +1,41 @@
--TEST--
enum 2
--FILE--
<?php
enum T: string
{
case I = 'int';
case S = 'string';
}
final class TestSpa
{
private const F = [
'1' => ['d' => '', 't' => T::S],
'2' => ['d' => 1, 't' => T::I],
'3' => ['d' => 123, 't' => T::S],
];
public static function E(): array
{
return self::F;
}
}
function main()
{
foreach (TestSpa::E() as $n => $f) {
$ok = match ($f['t']) {
T::I => is_int($f['d']),
T::S => is_string($f['d']),
};
echo $ok? " pass {$n} => [{$f['d']}, {$f['t']->value}]\n": " fail {$n} 元组非法\n";
}
}
?>
--EXPECT--
pass 1 => [, string]
pass 2 => [1, int]
fail 3 元组非法

@ -0,0 +1,30 @@
--TEST--
enum 2
--FILE--
<?php
enum TestEnum
{
case FOO;
case BAR;
}
final class TestSpa
{
public const F = [
TestEnum::FOO,
TestEnum::BAR,
];
}
function main()
{
var_dump(TestSpa::F);
}
?>
--EXPECT--
array(2) {
[0]=>
enum(TestEnum::FOO)
[1]=>
enum(TestEnum::BAR)
}

@ -0,0 +1,31 @@
--TEST--
enum 2
--FILE--
<?php
enum TestEnum: string
{
case FOO = TestSpa::F;
case BAR = 'bar';
}
final class TestSpa
{
public const F = 'foo';
}
function main()
{
var_dump(TestEnum::cases());
var_dump(TestEnum::FOO);
var_dump((string) TestEnum::FOO->value);
}
?>
--EXPECT--
array(2) {
[0]=>
enum(TestEnum::FOO)
[1]=>
enum(TestEnum::BAR)
}
enum(TestEnum::FOO)
string(3) "foo"
Loading…
Cancel
Save