-
Notifications
You must be signed in to change notification settings - Fork 8k
Open
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 5295fc0 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()}");
}Reactions are currently unavailable