php / php/php-src

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

Ouverte
#19,426 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Feature Status: Needs Triage Stubs
Langage dominant
C
Étoiles
40.4k
Forks
8.1k
Merge moyen
2 j 13 h
PR mergées (30 j)
96

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez dans build/gen_stub.php avec EnumCaseInfo, la gestion des cas d’enum dans handleStatements() et les chemins existants d’analyse de DocBlock et de EvaluatedValue. Examinez l’approche parseEnumCase proposée et ajoutez des tests pour @cvalue sur les cas d’enum backed. Le travail est terminé lorsque le traitement des stubs génère un arginfo qui lie les valeurs d’enum C documentées sans le contournement par constante privée.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
php
Domaine
build-system, tooling
Type d'issue
Fonctionnalité
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
42/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.