@@ -122,17 +122,19 @@ function processStubFile(string $stubFile, Context $context, bool $includeOnly =
122
122
echo "Saved $ arginfoFile \n" ;
123
123
}
124
124
125
- if ($ fileInfo ->generateLegacyArginfoForPhpVersionId !== null && $ fileInfo -> generateLegacyArginfoForPhpVersionId < PHP_80_VERSION_ID ) {
125
+ if ($ fileInfo ->shouldGenerateLegacyArginfo () ) {
126
126
$ legacyFileInfo = clone $ fileInfo ;
127
+ $ legacyFileInfo ->legacyArginfoGeneration = true ;
128
+ $ phpVersionIdMinimumCompatibility = $ legacyFileInfo ->getMinimumPhpVersionIdCompatibility ();
127
129
128
130
foreach ($ legacyFileInfo ->getAllFuncInfos () as $ funcInfo ) {
129
- $ funcInfo ->discardInfoForOldPhpVersions ();
131
+ $ funcInfo ->discardInfoForOldPhpVersions ($ phpVersionIdMinimumCompatibility );
130
132
}
131
- foreach ($ legacyFileInfo ->getAllConstInfos () as $ constInfo ) {
132
- $ constInfo ->discardInfoForOldPhpVersions ();
133
+ foreach ($ legacyFileInfo ->getAllClassInfos () as $ classInfo ) {
134
+ $ classInfo ->discardInfoForOldPhpVersions ($ phpVersionIdMinimumCompatibility );
133
135
}
134
- foreach ($ legacyFileInfo ->getAllPropertyInfos () as $ propertyInfo ) {
135
- $ propertyInfo ->discardInfoForOldPhpVersions ();
136
+ foreach ($ legacyFileInfo ->getAllConstInfos () as $ constInfo ) {
137
+ $ constInfo ->discardInfoForOldPhpVersions ($ phpVersionIdMinimumCompatibility );
136
138
}
137
139
138
140
$ arginfoCode = generateArgInfoCode (
@@ -1532,14 +1534,18 @@ public function getOptimizerInfo(): ?string {
1532
1534
return "\tF " . $ this ->return ->refcount . '(" ' . addslashes ($ this ->name ->__toString ()) . '", ' . $ type ->toOptimizerTypeMask () . "), \n" ;
1533
1535
}
1534
1536
1535
- public function discardInfoForOldPhpVersions (): void {
1537
+ public function discardInfoForOldPhpVersions (? int $ minimumPhpVersionIdCompatibility ): void {
1536
1538
$ this ->attributes = [];
1537
1539
$ this ->return ->type = null ;
1540
+ $ this ->framelessFunctionInfos = [];
1541
+ $ this ->exposedDocComment = null ;
1542
+ $ this ->supportsCompileTimeEval = false ;
1538
1543
foreach ($ this ->args as $ arg ) {
1539
1544
$ arg ->type = null ;
1540
1545
$ arg ->defaultValue = null ;
1541
1546
$ arg ->attributes = [];
1542
1547
}
1548
+ $ this ->minimumPhpVersionIdCompatibility = $ minimumPhpVersionIdCompatibility ;
1543
1549
}
1544
1550
1545
1551
/** @return array<int, string[]> */
@@ -2127,6 +2133,15 @@ public function __clone()
2127
2133
$this->args[$key] = clone $argInfo;
2128
2134
}
2129
2135
$this->return = clone $this->return;
2136
+ foreach ($this->attributes as $key => $attribute) {
2137
+ $this->attributes[$key] = clone $attribute;
2138
+ }
2139
+ foreach ($this->framelessFunctionInfos as $key => $framelessFunctionInfo) {
2140
+ $this->framelessFunctionInfos[$key] = clone $framelessFunctionInfo;
2141
+ }
2142
+ if ($this->exposedDocComment) {
2143
+ $this->exposedDocComment = clone $this->exposedDocComment;
2144
+ }
2130
2145
}
2131
2146
}
2132
2147
@@ -2355,7 +2370,7 @@ abstract protected function getFieldSynopsisName(): string;
2355
2370
/** @param array<string, ConstInfo> $allConstInfos */
2356
2371
abstract protected function getFieldSynopsisValueString(array $allConstInfos): ?string;
2357
2372
2358
- abstract public function discardInfoForOldPhpVersions(): void;
2373
+ abstract public function discardInfoForOldPhpVersions(?int $minimumPhpVersionIdCompatibility ): void;
2359
2374
2360
2375
protected function addTypeToFieldSynopsis(DOMDocument $doc, DOMElement $fieldsynopsisElement): void
2361
2376
{
@@ -2628,17 +2643,19 @@ public function getPredefinedConstantEntry(DOMDocument $doc, int $indentationLev
2628
2643
return $entryElement;
2629
2644
}
2630
2645
2631
- public function discardInfoForOldPhpVersions(): void {
2646
+ public function discardInfoForOldPhpVersions(?int $phpVersionIdMinimumCompatibility ): void {
2632
2647
$this->type = null;
2633
2648
$this->flags &= ~Modifiers::FINAL;
2634
2649
$this->isDeprecated = false;
2635
2650
$this->attributes = [];
2651
+ $this->phpVersionIdMinimumCompatibility = $phpVersionIdMinimumCompatibility;
2636
2652
}
2637
2653
2638
2654
/** @param array<string, ConstInfo> $allConstInfos */
2639
2655
public function getDeclaration(array $allConstInfos): string
2640
2656
{
2641
- $simpleType = ($this->phpDocType ?? $this->type)->tryToSimpleType();
2657
+ $type = $this->phpDocType ?? $this->type;
2658
+ $simpleType = $type ? $type->tryToSimpleType() : null;
2642
2659
if ($simpleType && $simpleType->name === "mixed") {
2643
2660
$simpleType = null;
2644
2661
}
@@ -2909,10 +2926,11 @@ protected function getFieldSynopsisValueString(array $allConstInfos): ?string
2909
2926
return $this->defaultValueString;
2910
2927
}
2911
2928
2912
- public function discardInfoForOldPhpVersions(): void {
2929
+ public function discardInfoForOldPhpVersions(?int $phpVersionIdMinimumCompatibility ): void {
2913
2930
$this->type = null;
2914
2931
$this->flags &= ~Modifiers::READONLY;
2915
2932
$this->attributes = [];
2933
+ $this->phpVersionIdMinimumCompatibility = $phpVersionIdMinimumCompatibility;
2916
2934
}
2917
2935
2918
2936
/** @param array<string, ConstInfo> $allConstInfos */
@@ -2940,7 +2958,6 @@ public function getDeclaration(array $allConstInfos): string {
2940
2958
2941
2959
$code .= "\tzend_string *property_{$propertyName}_name = zend_string_init(\"$propertyName\", sizeof(\"$propertyName\") - 1, 1);\n";
2942
2960
$nameCode = "property_{$propertyName}_name";
2943
- $typeCode = $this->getTypeCode($propertyName, $code);
2944
2961
2945
2962
if ($this->exposedDocComment) {
2946
2963
$commentCode = "property_{$propertyName}_comment";
@@ -2956,7 +2973,14 @@ public function getDeclaration(array $allConstInfos): string {
2956
2973
} else {
2957
2974
$template = "\t";
2958
2975
}
2959
- $template .= "zend_declare_typed_property(class_entry, $nameCode, &$zvalName, %s, $commentCode, $typeCode);\n";
2976
+
2977
+ if ($this->phpVersionIdMinimumCompatibility === null || $this->phpVersionIdMinimumCompatibility >= PHP_80_VERSION_ID) {
2978
+ $typeCode = $this->getTypeCode($propertyName, $code);
2979
+ $template .= "zend_declare_typed_property(class_entry, $nameCode, &$zvalName, %s, $commentCode, $typeCode);\n";
2980
+ } else {
2981
+ $template .= "zend_declare_property_ex(class_entry, $nameCode, &$zvalName, %s, $commentCode);\n";
2982
+ }
2983
+
2960
2984
$flagsCode = generateVersionDependentFlagCode(
2961
2985
$template,
2962
2986
$this->getFlagsByPhpVersion(),
@@ -3007,6 +3031,12 @@ public function __clone()
3007
3031
if ($this->type) {
3008
3032
$this->type = clone $this->type;
3009
3033
}
3034
+ foreach ($this->attributes as $key => $attribute) {
3035
+ $this->attributes[$key] = clone $attribute;
3036
+ }
3037
+ if ($this->exposedDocComment) {
3038
+ $this->exposedDocComment = clone $this->exposedDocComment;
3039
+ }
3010
3040
}
3011
3041
}
3012
3042
@@ -3383,6 +3413,19 @@ private function getFlagsByPhpVersion(): array
3383
3413
];
3384
3414
}
3385
3415
3416
+ public function discardInfoForOldPhpVersions(?int $phpVersionIdMinimumCompatibility): void {
3417
+ $this->attributes = [];
3418
+ $this->flags &= ~Modifiers::READONLY;
3419
+ $this->exposedDocComment = null;
3420
+ $this->isStrictProperties = false;
3421
+ $this->isNotSerializable = false;
3422
+
3423
+ foreach ($this->propertyInfos as $propertyInfo) {
3424
+ $propertyInfo->discardInfoForOldPhpVersions($phpVersionIdMinimumCompatibility);
3425
+ }
3426
+ $this->phpVersionIdMinimumCompatibility = $phpVersionIdMinimumCompatibility;
3427
+ }
3428
+
3386
3429
/**
3387
3430
* @param array<string, ClassInfo> $classMap
3388
3431
* @param array<string, ConstInfo> $allConstInfos
@@ -3801,13 +3844,25 @@ private function createIncludeElement(DOMDocument $doc, string $query): DOMEleme
3801
3844
3802
3845
public function __clone()
3803
3846
{
3847
+ foreach ($this->constInfos as $key => $constInfo) {
3848
+ $this->constInfos[$key] = clone $constInfo;
3849
+ }
3850
+
3804
3851
foreach ($this->propertyInfos as $key => $propertyInfo) {
3805
3852
$this->propertyInfos[$key] = clone $propertyInfo;
3806
3853
}
3807
3854
3808
3855
foreach ($this->funcInfos as $key => $funcInfo) {
3809
3856
$this->funcInfos[$key] = clone $funcInfo;
3810
3857
}
3858
+
3859
+ foreach ($this->attributes as $key => $attribute) {
3860
+ $this->attributes[$key] = clone $attribute;
3861
+ }
3862
+
3863
+ if ($this->exposedDocComment) {
3864
+ $this->exposedDocComment = clone $this->exposedDocComment;
3865
+ }
3811
3866
}
3812
3867
3813
3868
/**
@@ -3848,9 +3903,10 @@ class FileInfo {
3848
3903
public array $classInfos = [];
3849
3904
public bool $generateFunctionEntries = false;
3850
3905
public string $declarationPrefix = "";
3851
- public ?int $generateLegacyArginfoForPhpVersionId = null;
3852
3906
public bool $generateClassEntries = false;
3853
3907
public bool $isUndocumentable = false;
3908
+ public bool $legacyArginfoGeneration = false;
3909
+ private ?int $minimumPhpVersionIdCompatibility = null;
3854
3910
3855
3911
/**
3856
3912
* @return iterable<FuncInfo>
@@ -3880,16 +3936,20 @@ public function getAllConstInfos(): array {
3880
3936
}
3881
3937
3882
3938
/**
3883
- * @return iterable<PropertyInfo >
3939
+ * @return iterable<ClassInfo >
3884
3940
*/
3885
- public function getAllPropertyInfos (): iterable {
3941
+ public function getAllClassInfos (): iterable {
3886
3942
foreach ($this->classInfos as $classInfo) {
3887
- yield from $classInfo->propertyInfos ;
3943
+ yield $classInfo;
3888
3944
}
3889
3945
}
3890
3946
3891
3947
public function __clone()
3892
3948
{
3949
+ foreach ($this->constInfos as $key => $constInfo) {
3950
+ $this->constInfos[$key] = clone $constInfo;
3951
+ }
3952
+
3893
3953
foreach ($this->funcInfos as $key => $funcInfo) {
3894
3954
$this->funcInfos[$key] = clone $funcInfo;
3895
3955
}
@@ -3898,6 +3958,26 @@ public function __clone()
3898
3958
$this->classInfos[$key] = clone $classInfo;
3899
3959
}
3900
3960
}
3961
+
3962
+ public function setMinimumPhpVersionIdCompatibility(?int $minimumPhpVersionIdCompatibility) {
3963
+ $this->minimumPhpVersionIdCompatibility = $minimumPhpVersionIdCompatibility;
3964
+ }
3965
+
3966
+ public function getMinimumPhpVersionIdCompatibility(): ?int {
3967
+ // Non-legacy arginfo files are always PHP 8.0+ compatible
3968
+ if (!$this->legacyArginfoGeneration &&
3969
+ $this->minimumPhpVersionIdCompatibility !== null &&
3970
+ $this->minimumPhpVersionIdCompatibility < PHP_80_VERSION_ID
3971
+ ) {
3972
+ return PHP_80_VERSION_ID;
3973
+ }
3974
+
3975
+ return $this->minimumPhpVersionIdCompatibility;
3976
+ }
3977
+
3978
+ public function shouldGenerateLegacyArginfo(): bool {
3979
+ return $this->minimumPhpVersionIdCompatibility !== null && $this->minimumPhpVersionIdCompatibility < PHP_80_VERSION_ID;
3980
+ }
3901
3981
}
3902
3982
3903
3983
class DocCommentTag {
@@ -4541,7 +4621,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4541
4621
$stmt->getComments(),
4542
4622
$cond,
4543
4623
$fileInfo->isUndocumentable,
4544
- $fileInfo->generateLegacyArginfoForPhpVersionId ,
4624
+ $fileInfo->getMinimumPhpVersionIdCompatibility() ,
4545
4625
[]
4546
4626
);
4547
4627
}
@@ -4557,7 +4637,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4557
4637
$stmt,
4558
4638
$cond,
4559
4639
$fileInfo->isUndocumentable,
4560
- $fileInfo->generateLegacyArginfoForPhpVersionId
4640
+ $fileInfo->getMinimumPhpVersionIdCompatibility()
4561
4641
);
4562
4642
continue;
4563
4643
}
@@ -4588,7 +4668,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4588
4668
$classStmt->getComments(),
4589
4669
$cond,
4590
4670
$fileInfo->isUndocumentable,
4591
- $fileInfo->generateLegacyArginfoForPhpVersionId ,
4671
+ $fileInfo->getMinimumPhpVersionIdCompatibility() ,
4592
4672
createAttributes($classStmt->attrGroups)
4593
4673
);
4594
4674
}
@@ -4604,7 +4684,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4604
4684
$classStmt->type,
4605
4685
$classStmt->getComments(),
4606
4686
$prettyPrinter,
4607
- $fileInfo->generateLegacyArginfoForPhpVersionId ,
4687
+ $fileInfo->getMinimumPhpVersionIdCompatibility() ,
4608
4688
createAttributes($classStmt->attrGroups)
4609
4689
);
4610
4690
}
@@ -4620,7 +4700,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4620
4700
$classStmt,
4621
4701
$cond,
4622
4702
$fileInfo->isUndocumentable,
4623
- $fileInfo->generateLegacyArginfoForPhpVersionId
4703
+ $fileInfo->getMinimumPhpVersionIdCompatibility()
4624
4704
);
4625
4705
} else if ($classStmt instanceof Stmt\EnumCase) {
4626
4706
$enumCaseInfos[] = new EnumCaseInfo(
@@ -4631,7 +4711,7 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
4631
4711
}
4632
4712
4633
4713
$fileInfo->classInfos[] = parseClass(
4634
- $className, $stmt, $constInfos, $propertyInfos, $methodInfos, $enumCaseInfos, $cond, $fileInfo->generateLegacyArginfoForPhpVersionId , $fileInfo->isUndocumentable
4714
+ $className, $stmt, $constInfos, $propertyInfos, $methodInfos, $enumCaseInfos, $cond, $fileInfo->getMinimumPhpVersionIdCompatibility() , $fileInfo->isUndocumentable
4635
4715
);
4636
4716
continue;
4637
4717
}
@@ -4678,11 +4758,11 @@ protected function pName_FullyQualified(Name\FullyQualified $node): string {
4678
4758
throw new Exception(
4679
4759
"Legacy PHP version must be one of: \"" . PHP_70_VERSION_ID . "\" (PHP 7.0), \"" . PHP_80_VERSION_ID . "\" (PHP 8.0), " .
4680
4760
"\"" . PHP_81_VERSION_ID . "\" (PHP 8.1), \"" . PHP_82_VERSION_ID . "\" (PHP 8.2), \"" . PHP_83_VERSION_ID . "\" (PHP 8.3), " .
4681
- "\"" . $tag->value . "\" provided"
4761
+ "\"" . PHP_84_VERSION_ID . "\" (PHP 8.4), \"" . $tag->value . "\" provided"
4682
4762
);
4683
4763
}
4684
4764
4685
- $fileInfo->generateLegacyArginfoForPhpVersionId = $tag->value ? (int) $tag->value : PHP_70_VERSION_ID;
4765
+ $fileInfo->setMinimumPhpVersionIdCompatibility( $tag->value ? (int) $tag->value : PHP_70_VERSION_ID) ;
4686
4766
} else if ($tag->name === 'generate-class-entries') {
4687
4767
$fileInfo->generateClassEntries = true;
4688
4768
$fileInfo->declarationPrefix = $tag->value ? $tag->value . " " : "";
@@ -4705,7 +4785,7 @@ function funcInfoToCode(FileInfo $fileInfo, FuncInfo $funcInfo): string {
4705
4785
$code = '';
4706
4786
$returnType = $funcInfo->return->type;
4707
4787
$isTentativeReturnType = $funcInfo->return->tentativeReturnType;
4708
- $php81MinimumCompatibility = $fileInfo->generateLegacyArginfoForPhpVersionId === null || $fileInfo->generateLegacyArginfoForPhpVersionId >= PHP_81_VERSION_ID;
4788
+ $php81MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_81_VERSION_ID;
4709
4789
4710
4790
if ($returnType !== null) {
4711
4791
if ($isTentativeReturnType && !$php81MinimumCompatibility) {
@@ -4864,6 +4944,14 @@ function generateArgInfoCode(
4864
4944
$code = "/* This is a generated file, edit the .stub.php file instead.\n"
4865
4945
. " * Stub hash: $stubHash */\n";
4866
4946
4947
+ $minimumPhpVersionIdCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility();
4948
+ if ($minimumPhpVersionIdCompatibility !== null) {
4949
+ $code .= "\nZEND_STATIC_ASSERT(PHP_VERSION_ID >= $minimumPhpVersionIdCompatibility, ";
4950
+ $code .= "\"{$stubFilenameWithoutExtension}_arginfo.h only supports ";
4951
+ $code .= "PHP version ID $minimumPhpVersionIdCompatibility or newer, \"\n";
4952
+ $code .= "\t\"but it is included on an older PHP version\");\n";
4953
+ }
4954
+
4867
4955
$generatedFuncInfos = [];
4868
4956
4869
4957
$argInfoCode = generateCodeWithConditions(
@@ -4924,10 +5012,10 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat
4924
5012
}
4925
5013
}
4926
5014
4927
- $php80MinimumCompatibility = $fileInfo->generateLegacyArginfoForPhpVersionId === null || $fileInfo->generateLegacyArginfoForPhpVersionId >= PHP_80_VERSION_ID;
5015
+ $php80MinimumCompatibility = $fileInfo->getMinimumPhpVersionIdCompatibility() === null || $fileInfo->getMinimumPhpVersionIdCompatibility() >= PHP_80_VERSION_ID;
4928
5016
4929
5017
if ($fileInfo->generateClassEntries) {
4930
- if ($attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->generateLegacyArginfoForPhpVersionId , null)) {
5018
+ if ($attributeInitializationCode = generateFunctionAttributeInitialization($fileInfo->funcInfos, $allConstInfos, $fileInfo->getMinimumPhpVersionIdCompatibility() , null)) {
4931
5019
if (!$php80MinimumCompatibility) {
4932
5020
$attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ")" . $attributeInitializationCode . "#endif\n";
4933
5021
}
0 commit comments