php / php/php-src

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

Đang mở
#19,426 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Feature Status: Needs Triage Stubs
Ngôn ngữ chính
C
Star
40.4k
Fork
8.1k
Merge trung bình
2 ngày 13 giờ
Pull request đã merge (30 ngày)
96

Mô tả

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()}");
                 }

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong build/gen_stub.php với EnumCaseInfo, phần xử lý enum case trong handleStatements(), cùng các luồng parsing DocBlock và EvaluatedValue hiện có. Xem xét cách tiếp cận parseEnumCase được đề xuất và thêm các kiểm thử cho @cvalue trên các enum case backed. Hoàn tất khi quá trình xử lý stub tạo ra arginfo liên kết các giá trị enum C được ghi nhận trong tài liệu mà không cần workaround bằng hằng private.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
php
Lĩnh vực
build-system, tooling
Loại issue
Tính năng
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
42/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.