Skip to content

Commit 319eede

Browse files
authored
Merge pull request #2498 from zephir-lang/niden/stubs-typed-constants
Adding support for typed constants (stubs) for php 8.3+
2 parents b749cca + 648c1f4 commit 319eede

2 files changed

Lines changed: 74 additions & 1 deletion

File tree

src/Stubs/Generator.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use function is_dir;
3232
use function key;
3333
use function mkdir;
34+
use function preg_match;
3435
use function realpath;
3536
use function sprintf;
3637
use function str_ireplace;
@@ -40,6 +41,7 @@
4041

4142
use const DIRECTORY_SEPARATOR;
4243
use const PHP_EOL;
44+
use const PHP_VERSION_ID;
4345

4446
class Generator
4547
{
@@ -218,7 +220,8 @@ protected function buildClass(Definition $class, string $indent, string $banner)
218220

219221
protected function buildConstant(Constant $constant, string $indent): string
220222
{
221-
$source = 'const ' . $constant->getName();
223+
$type = PHP_VERSION_ID >= 80300 ? $this->extractVarTypeFromDocBlock($constant->getDocBlock()) : '';
224+
$source = 'const ' . ($type !== '' ? $type . ' ' : '') . $constant->getName();
222225

223226
$value = $this->wrapPHPValue([
224227
'default' => $constant->getValue(),
@@ -427,6 +430,19 @@ protected function wrapPHPValue(array $parameter): string
427430
return (string)$returnValue;
428431
}
429432

433+
private function extractVarTypeFromDocBlock(?string $docBlock): string
434+
{
435+
if ($docBlock === null) {
436+
return '';
437+
}
438+
439+
if (preg_match('/@var\s+([\w\\\\|]+)/', $docBlock, $matches)) {
440+
return $matches[1];
441+
}
442+
443+
return '';
444+
}
445+
430446
private function fetchDocBlock(?string $docBlock, string $indent): string
431447
{
432448
$docBlock = (new DocBlock($docBlock, $indent))->__toString();

tests/Zephir/Stubs/GeneratorTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,63 @@ public function constantProvider(): array
326326
];
327327
}
328328

329+
public function typedConstantProvider(): array
330+
{
331+
$typed = PHP_VERSION_ID >= 80300;
332+
$docPart = "/**\n * @var %s\n */\n";
333+
334+
return [
335+
[
336+
'int', 1, '@var int',
337+
sprintf($docPart, 'int') . ($typed ? 'const int TEST = 1;' : 'const TEST = 1;'),
338+
],
339+
[
340+
'string', 'Foo', '@var string',
341+
sprintf($docPart, 'string') . ($typed ? "const string TEST = 'Foo';" : "const TEST = 'Foo';"),
342+
],
343+
[
344+
'bool', 1, '@var bool',
345+
sprintf($docPart, 'bool') . ($typed ? 'const bool TEST = 1;' : 'const TEST = 1;'),
346+
],
347+
[
348+
'string', 'bar', null, "const TEST = 'bar';",
349+
],
350+
];
351+
}
352+
353+
/**
354+
* @dataProvider typedConstantProvider
355+
*
356+
* @throws \ReflectionException
357+
*/
358+
public function testShouldBuildTypedConstant(string $type, mixed $value, ?string $docBlock, string $expected): void
359+
{
360+
if (Os::isWindows()) {
361+
$this->markTestSkipped('Warning: Strings contain different line endings!');
362+
}
363+
364+
$buildClass = $this->getMethod('buildConstant');
365+
366+
$classConstant = new Constant(
367+
'TEST',
368+
[
369+
'type' => $type,
370+
'value' => $value,
371+
],
372+
$docBlock
373+
);
374+
375+
$actual = $buildClass->invokeArgs(
376+
$this->testClass,
377+
[
378+
$classConstant,
379+
'',
380+
]
381+
);
382+
383+
$this->assertSame($expected, $actual);
384+
}
385+
329386
/**
330387
* @dataProvider constantProvider
331388
*

0 commit comments

Comments
 (0)