php / php/php-src

gen_stub.php support for @cvalue DocBlock annotation for backed enum cases

未关闭
#19,426 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Feature Status: Needs Triage Stubs
主要语言
C
星标
40.4k
派生
8.1k
平均合并
2 天 13 小时
30 天内合并 PR
96

描述

Description

I am trying to use a *.stub.php file to create an *_arginfo.h file which will bind third-party c enum values to a PHP backed enum.

My naïve approach was:

enum MyEnum: int {
    /**
     * @var int
     * @cvalue MY_C_ENUM_VALUE1
     */
    case Value1 = UNKNOWN;
}

but that did not work.

A rather verbose and unintuitive workaround is:

enum MyEnum: int {
    /**
     * @var int
     * @cvalue MY_C_ENUM_VALUE1
     */
    private const VALUE1 = UNKNOWN
    case Value1 = MyEnum::VALUE1;
}

Ideally, the type is inferred from the enum declaration but using @var works for me.

I'm using the 8.4 branch at commit 5295fc07d5985d962df342f65d66fc0fb89f5edb for my tests.

@kocsismate included because you are a volunteer for gen_stub.php.

Please find below a very simple implementation of what I try to achieve. While it does what I want it is not extensively tested and has probably side effects. If this is worth a PR please let me know. Any guidance on missing bits and pieces is very welcome. Obviously, tests have to be added.

---
 build/gen_stub.php | 62 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 4 deletions(-)

diff --git a/build/gen_stub.php b/build/gen_stub.php
index f1d8b43862e..219c9af2cc4 100755
--- a/build/gen_stub.php
+++ b/build/gen_stub.php
@@ -3096,10 +3096,19 @@ public function __clone()
 class EnumCaseInfo {
     public string $name;
     public ?Expr $value;
+    public ?SimpleType $constType;
+    public ?string $cConstName;

-    public function __construct(string $name, ?Expr $value) {
+    public function __construct(
+        string $name,
+        ?Expr $value,
+        ?SimpleType $constType,
+        ?string $cConstName
+    ) {
         $this->name = $name;
         $this->value = $value;
+        $this->constType = $constType;
+        $this->cConstName = $cConstName;
     }

     /** @param array<string, ConstInfo> $allConstInfos */
@@ -3108,7 +3117,12 @@ public function getDeclaration(array $allConstInfos): string {
         if ($this->value === null) {
             $code = "\n\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", NULL);\n";
         } else {
-            $value = EvaluatedValue::createFromExpression($this->value, null, null, $allConstInfos);
+            $value = EvaluatedValue::createFromExpression(
+                $this->value,
+                $this->constType,
+                $this->cConstName,
+                $allConstInfos
+            );

             $zvalName = "enum_case_{$escapedName}_value";
             $code = "\n" . $value->initializeZval($zvalName);
@@ -4444,6 +4458,43 @@ function parseConstLike(
     );
 }

+function parseEnumCase(
+    string $name,
+    ?Expr $value,
+    array $comments
+): EnumCaseInfo {
+    $cConstName = null;
+    $phpDocType = null;
+    if ($comments) {
+        $tags = parseDocComments($comments);
+        foreach ($tags as $tag) {
+            if ($tag->name === 'var') {
+                $phpDocType = $tag->getType();
+            } elseif ($tag->name === 'cvalue') {
+                $cConstName = $tag->value;
+            }
+        }
+    }
+
+    $constPhpDocType = $phpDocType
+        ? SimpleType::fromString($phpDocType)
+        : null;
+
+    // Toto: infer type from enum declaration
+    if ($cConstName && $constPhpDocType
+        && !($constPhpDocType->name === 'int' || $constPhpDocType->name === 'string')
+    ) {
+        throw new Exception("Backed enums must be of type int or string");
+    }
+
+    return new EnumCaseInfo(
+        $name,
+        $value,
+        $constPhpDocType,
+        $cConstName
+    );
+}
+
 /**
  * @param array<int, array<int, AttributeGroup> $attributes
  */
@@ -4810,8 +4861,11 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
                         $fileInfo->getMinimumPhpVersionIdCompatibility()
                     );
                 } else if ($classStmt instanceof Stmt\EnumCase) {
-                    $enumCaseInfos[] = new EnumCaseInfo(
-                        $classStmt->name->toString(), $classStmt->expr);
+                    $enumCaseInfos[] = parseEnumCase(
+                        $classStmt->name->toString(),
+                        $classStmt->expr,
+                        $classStmt->getComments()
+                    );
                 } else {
                     throw new Exception("Not implemented {$classStmt->getType()}");
                 }

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 build/gen_stub.php 中的 EnumCaseInfo、handleStatements() 中对 enum case 的处理,以及现有的 DocBlock 解析和 EvaluatedValue 路径开始。审查提议的 parseEnumCase 方法,并为 backed enum case 上的 @cvalue 添加测试。完成的标准是:stub 处理会生成 arginfo,将文档中记录的 C enum 值绑定起来,而无需使用 private-constant workaround。

由索引模型根据 Issue 内容生成。

评估

技术栈
php
领域
build-system, tooling
Issue 类型
功能
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
42/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。