@@ -3319,8 +3319,12 @@ public function __construct(string $class, array $args) {
33193319 $ this ->args = $ args ;
33203320 }
33213321
3322- /** @param array<string, ConstInfo> $allConstInfos */
3323- public function generateCode (string $ invocation , string $ nameSuffix , array $ allConstInfos , ?int $ phpVersionIdMinimumCompatibility ): string {
3322+ /**
3323+ * @param array<string, ConstInfo> $allConstInfos
3324+ * @param array<string, string> &$declaredStrings Map of string content to
3325+ * the name of a zend_string already created with that content
3326+ */
3327+ public function generateCode (string $ invocation , string $ nameSuffix , array $ allConstInfos , ?int $ phpVersionIdMinimumCompatibility , array &$ declaredStrings = []): string {
33243328 $ escapedAttributeName = strtr ($ this ->class , '\\' , '_ ' );
33253329 [$ stringInit , $ nameCode , $ stringRelease ] = StringBuilder::getString (
33263330 "attribute_name_ {$ escapedAttributeName }_ $ nameSuffix " ,
@@ -3344,6 +3348,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
33443348 );
33453349 if ($ strInit === '' ) {
33463350 $ initValue = "\tZVAL_STR(&attribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].value, $ strUse); \n" ;
3351+ } elseif (isset ($ declaredStrings [$ strVal ])) {
3352+ $ strUse = $ declaredStrings [$ strVal ];
3353+ $ initValue = "\tZVAL_STR_COPY(&attribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].value, $ strUse); \n" ;
33473354 }
33483355 }
33493356 if ($ initValue === '' ) {
@@ -3353,6 +3360,9 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
33533360 true ,
33543361 "attribute_ {$ escapedAttributeName }_ {$ nameSuffix }_arg {$ i }_str "
33553362 );
3363+ if ($ arg ->value instanceof Node \Scalar \String_) {
3364+ $ declaredStrings [$ arg ->value ->value ] = "attribute_ {$ escapedAttributeName }_ {$ nameSuffix }_arg {$ i }_str " ;
3365+ }
33563366 } else {
33573367 $ code .= $ initValue ;
33583368 }
@@ -3603,6 +3613,8 @@ function (Name $item) {
36033613 $ php80CondEnd = "#endif \n" ;
36043614 }
36053615
3616+ $ declaredStrings = [];
3617+
36063618 if (!empty ($ this ->attributes )) {
36073619 $ code .= $ php80CondStart ;
36083620
@@ -3611,26 +3623,27 @@ function (Name $item) {
36113623 "zend_add_class_attribute(class_entry " ,
36123624 "class_ {$ escapedName }_ $ key " ,
36133625 $ allConstInfos ,
3614- $ this ->phpVersionIdMinimumCompatibility
3626+ $ this ->phpVersionIdMinimumCompatibility ,
3627+ $ declaredStrings
36153628 );
36163629 }
36173630
36183631 $ code .= $ php80CondEnd ;
36193632 }
36203633
3621- if ($ attributeInitializationCode = generateConstantAttributeInitialization ($ this ->constInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility , $ this ->cond )) {
3634+ if ($ attributeInitializationCode = generateConstantAttributeInitialization ($ this ->constInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility , $ this ->cond , $ declaredStrings )) {
36223635 $ code .= $ php80CondStart ;
36233636 $ code .= "\n" . $ attributeInitializationCode ;
36243637 $ code .= $ php80CondEnd ;
36253638 }
36263639
3627- if ($ attributeInitializationCode = generatePropertyAttributeInitialization ($ this ->propertyInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility )) {
3640+ if ($ attributeInitializationCode = generatePropertyAttributeInitialization ($ this ->propertyInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility , $ declaredStrings )) {
36283641 $ code .= $ php80CondStart ;
36293642 $ code .= "\n" . $ attributeInitializationCode ;
36303643 $ code .= $ php80CondEnd ;
36313644 }
36323645
3633- if ($ attributeInitializationCode = generateFunctionAttributeInitialization ($ this ->funcInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility , $ this ->cond )) {
3646+ if ($ attributeInitializationCode = generateFunctionAttributeInitialization ($ this ->funcInfos , $ allConstInfos , $ this ->phpVersionIdMinimumCompatibility , $ this ->cond , $ declaredStrings )) {
36343647 $ code .= $ php80CondStart ;
36353648 $ code .= "\n" . $ attributeInitializationCode ;
36363649 $ code .= $ php80CondEnd ;
@@ -5185,8 +5198,9 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat
51855198 $ php80MinimumCompatibility = $ fileInfo ->getMinimumPhpVersionIdCompatibility () === null || $ fileInfo ->getMinimumPhpVersionIdCompatibility () >= PHP_80_VERSION_ID ;
51865199
51875200 if ($ fileInfo ->generateClassEntries ) {
5188- $ attributeInitializationCode = generateFunctionAttributeInitialization ($ fileInfo ->funcInfos , $ allConstInfos , $ fileInfo ->getMinimumPhpVersionIdCompatibility (), null );
5189- $ attributeInitializationCode .= generateGlobalConstantAttributeInitialization ($ fileInfo ->constInfos , $ allConstInfos , $ fileInfo ->getMinimumPhpVersionIdCompatibility (), null );
5201+ $ declaredStrings = [];
5202+ $ attributeInitializationCode = generateFunctionAttributeInitialization ($ fileInfo ->funcInfos , $ allConstInfos , $ fileInfo ->getMinimumPhpVersionIdCompatibility (), null , $ declaredStrings );
5203+ $ attributeInitializationCode .= generateGlobalConstantAttributeInitialization ($ fileInfo ->constInfos , $ allConstInfos , $ fileInfo ->getMinimumPhpVersionIdCompatibility (), null , $ declaredStrings );
51905204 if ($ attributeInitializationCode ) {
51915205 if (!$ php80MinimumCompatibility ) {
51925206 $ attributeInitializationCode = "\n#if (PHP_VERSION_ID >= " . PHP_80_VERSION_ID . ") " . $ attributeInitializationCode . "#endif \n" ;
@@ -5244,12 +5258,16 @@ function generateFunctionEntries(?Name $className, array $funcInfos, ?string $co
52445258 return $ code ;
52455259}
52465260
5247- /** @param iterable<FuncInfo> $funcInfos */
5248- function generateFunctionAttributeInitialization (iterable $ funcInfos , array $ allConstInfos , ?int $ phpVersionIdMinimumCompatibility , ?string $ parentCond = null ): string {
5261+ /**
5262+ * @param iterable<FuncInfo> $funcInfos
5263+ * @param array<string, string> &$declaredStrings Map of string content to
5264+ * the name of a zend_string already created with that content
5265+ */
5266+ function generateFunctionAttributeInitialization (iterable $ funcInfos , array $ allConstInfos , ?int $ phpVersionIdMinimumCompatibility , ?string $ parentCond = null , array &$ declaredStrings = []): string {
52495267 return generateCodeWithConditions (
52505268 $ funcInfos ,
52515269 "" ,
5252- static function (FuncInfo $ funcInfo ) use ($ allConstInfos , $ phpVersionIdMinimumCompatibility ) {
5270+ static function (FuncInfo $ funcInfo ) use ($ allConstInfos , $ phpVersionIdMinimumCompatibility, & $ declaredStrings ) {
52535271 $ code = null ;
52545272
52555273 if ($ funcInfo ->name instanceof MethodName) {
@@ -5258,12 +5276,22 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52585276 $ functionTable = "CG(function_table) " ;
52595277 }
52605278
5279+ // Make sure we don't try and use strings that might only be
5280+ // conditionally available; string reuse is only among declarations
5281+ // that are always there
5282+ if ($ funcInfo ->cond ) {
5283+ $ useDeclared = [];
5284+ } else {
5285+ $ useDeclared = &$ declaredStrings ;
5286+ }
5287+
52615288 foreach ($ funcInfo ->attributes as $ key => $ attribute ) {
52625289 $ code .= $ attribute ->generateCode (
52635290 "zend_add_function_attribute(zend_hash_str_find_ptr( $ functionTable, \"" . $ funcInfo ->name ->getNameForAttributes () . "\", sizeof( \"" . $ funcInfo ->name ->getNameForAttributes () . "\") - 1) " ,
52645291 "func_ " . $ funcInfo ->name ->getNameForAttributes () . "_ $ key " ,
52655292 $ allConstInfos ,
5266- $ phpVersionIdMinimumCompatibility
5293+ $ phpVersionIdMinimumCompatibility ,
5294+ $ useDeclared
52675295 );
52685296 }
52695297
@@ -5273,7 +5301,8 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52735301 "zend_add_parameter_attribute(zend_hash_str_find_ptr( $ functionTable, \"" . $ funcInfo ->name ->getNameForAttributes () . "\", sizeof( \"" . $ funcInfo ->name ->getNameForAttributes () . "\") - 1), $ index " ,
52745302 "func_ {$ funcInfo ->name ->getNameForAttributes ()}_arg {$ index }_ $ key " ,
52755303 $ allConstInfos ,
5276- $ phpVersionIdMinimumCompatibility
5304+ $ phpVersionIdMinimumCompatibility ,
5305+ $ useDeclared
52775306 );
52785307 }
52795308 }
@@ -5287,12 +5316,15 @@ static function (FuncInfo $funcInfo) use ($allConstInfos, $phpVersionIdMinimumCo
52875316/**
52885317 * @param iterable<ConstInfo> $constInfos
52895318 * @param array<string, ConstInfo> $allConstInfos
5319+ * @param array<string, string> &$declaredStrings Map of string content to
5320+ * the name of a zend_string already created with that content
52905321 */
52915322function generateGlobalConstantAttributeInitialization (
52925323 iterable $ constInfos ,
52935324 array $ allConstInfos ,
52945325 ?int $ phpVersionIdMinimumCompatibility ,
5295- ?string $ parentCond = null
5326+ ?string $ parentCond = null ,
5327+ array &$ declaredStrings = []
52965328): string {
52975329 $ isConditional = false ;
52985330 if ($ phpVersionIdMinimumCompatibility !== null && $ phpVersionIdMinimumCompatibility < PHP_85_VERSION_ID ) {
@@ -5301,12 +5333,20 @@ function generateGlobalConstantAttributeInitialization(
53015333 $ code = generateCodeWithConditions (
53025334 $ constInfos ,
53035335 "" ,
5304- static function (ConstInfo $ constInfo ) use ($ allConstInfos , $ isConditional ) {
5336+ static function (ConstInfo $ constInfo ) use ($ allConstInfos , $ isConditional, & $ declaredStrings ) {
53055337 $ code = "" ;
53065338
53075339 if ($ constInfo ->attributes === []) {
53085340 return null ;
53095341 }
5342+ // Make sure we don't try and use strings that might only be
5343+ // conditionally available; string reuse is only among declarations
5344+ // that are always there
5345+ if ($ constInfo ->cond ) {
5346+ $ useDeclared = [];
5347+ } else {
5348+ $ useDeclared = &$ declaredStrings ;
5349+ }
53105350 $ constName = str_replace ('\\' , '\\\\' , $ constInfo ->name ->__toString ());
53115351 $ constVarName = 'const_ ' . $ constName ;
53125352
@@ -5321,7 +5361,8 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
53215361 "zend_add_global_constant_attribute( $ constVarName " ,
53225362 $ constVarName . "_ $ key " ,
53235363 $ allConstInfos ,
5324- PHP_85_VERSION_ID
5364+ PHP_85_VERSION_ID ,
5365+ $ useDeclared
53255366 );
53265367 }
53275368
@@ -5338,25 +5379,37 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $isConditional) {
53385379/**
53395380 * @param iterable<ConstInfo> $constInfos
53405381 * @param array<string, ConstInfo> $allConstInfos
5382+ * @param array<string, string> &$declaredStrings Map of string content to
5383+ * the name of a zend_string already created with that content
53415384 */
53425385function generateConstantAttributeInitialization (
53435386 iterable $ constInfos ,
53445387 array $ allConstInfos ,
53455388 ?int $ phpVersionIdMinimumCompatibility ,
5346- ?string $ parentCond = null
5389+ ?string $ parentCond = null ,
5390+ array &$ declaredStrings = []
53475391): string {
53485392 return generateCodeWithConditions (
53495393 $ constInfos ,
53505394 "" ,
5351- static function (ConstInfo $ constInfo ) use ($ allConstInfos , $ phpVersionIdMinimumCompatibility ) {
5395+ static function (ConstInfo $ constInfo ) use ($ allConstInfos , $ phpVersionIdMinimumCompatibility, & $ declaredStrings ) {
53525396 $ code = null ;
53535397
5398+ // Make sure we don't try and use strings that might only be
5399+ // conditionally available; string reuse is only among declarations
5400+ // that are always there
5401+ if ($ constInfo ->cond ) {
5402+ $ useDeclared = [];
5403+ } else {
5404+ $ useDeclared = &$ declaredStrings ;
5405+ }
53545406 foreach ($ constInfo ->attributes as $ key => $ attribute ) {
53555407 $ code .= $ attribute ->generateCode (
53565408 "zend_add_class_constant_attribute(class_entry, const_ " . $ constInfo ->name ->getDeclarationName (),
53575409 "const_ " . $ constInfo ->name ->getDeclarationName () . "_ $ key " ,
53585410 $ allConstInfos ,
5359- $ phpVersionIdMinimumCompatibility
5411+ $ phpVersionIdMinimumCompatibility ,
5412+ $ useDeclared
53605413 );
53615414 }
53625415
@@ -5369,11 +5422,14 @@ static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimum
53695422/**
53705423 * @param iterable<PropertyInfo> $propertyInfos
53715424 * @param array<string, ConstInfo> $allConstInfos
5425+ * @param array<string, string> &$declaredStrings Map of string content to
5426+ * the name of a zend_string already created with that content
53725427 */
53735428function generatePropertyAttributeInitialization (
53745429 iterable $ propertyInfos ,
53755430 array $ allConstInfos ,
5376- ?int $ phpVersionIdMinimumCompatibility
5431+ ?int $ phpVersionIdMinimumCompatibility ,
5432+ array &$ declaredStrings
53775433): string {
53785434 $ code = "" ;
53795435 foreach ($ propertyInfos as $ propertyInfo ) {
@@ -5382,7 +5438,8 @@ function generatePropertyAttributeInitialization(
53825438 "zend_add_property_attribute(class_entry, property_ " . $ propertyInfo ->name ->getDeclarationName (),
53835439 "property_ " . $ propertyInfo ->name ->getDeclarationName () . "_ " . $ key ,
53845440 $ allConstInfos ,
5385- $ phpVersionIdMinimumCompatibility
5441+ $ phpVersionIdMinimumCompatibility ,
5442+ $ declaredStrings
53865443 );
53875444 }
53885445 }
0 commit comments