php / php/php-src

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

Offen
#19,426 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Feature Status: Needs Triage Stubs
Vorherrschende Sprache
C
Sterne
40.4k
Forks
8.2k
Ø Merge
2 T. 13 Std.
Gemergte PRs (30 T.)
96

Beschreibung

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

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne in build/gen_stub.php mit EnumCaseInfo, der Behandlung von Enum-Cases in handleStatements() und den vorhandenen Pfaden für das DocBlock-Parsing und EvaluatedValue. Überprüfe den vorgeschlagenen parseEnumCase-Ansatz und füge Tests für @cvalue bei Backed-Enum-Cases hinzu. Erledigt ist die Aufgabe, wenn die Stub-Verarbeitung arginfo erzeugt, das die dokumentierten C-Enum-Werte bindet, ohne den Workaround mit privaten Konstanten.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
php
Bereich
build-system, tooling
Issue-Typ
Feature
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
42/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.