@@ -2955,14 +2955,7 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie
29552955 }
29562956}
29572957
2958- class PropertyInfo extends VariableLike
2959- {
2960- private /* readonly */ int $ classFlags ;
2961- public /* readonly */ PropertyName $ name ;
2962- private /* readonly */ ?Expr $ defaultValue ;
2963- private /* readonly */ ?string $ defaultValueString ;
2964- private /* readonly */ bool $ isDocReadonly ;
2965- private /* readonly */ bool $ isVirtual ;
2958+ class StringBuilder {
29662959
29672960 // Map possible variable names to the known string constant, see
29682961 // ZEND_KNOWN_STRINGS
@@ -3065,8 +3058,90 @@ class PropertyInfo extends VariableLike
30653058 "username " => "ZEND_STR_USERNAME " ,
30663059 "password " => "ZEND_STR_PASSWORD " ,
30673060 "clone " => "ZEND_STR_CLONE " ,
3061+ '8.0 ' => 'ZEND_STR_8_DOT_0 ' ,
3062+ '8.1 ' => 'ZEND_STR_8_DOT_1 ' ,
3063+ '8.2 ' => 'ZEND_STR_8_DOT_2 ' ,
3064+ '8.3 ' => 'ZEND_STR_8_DOT_3 ' ,
3065+ '8.4 ' => 'ZEND_STR_8_DOT_4 ' ,
3066+ '8.5 ' => 'ZEND_STR_8_DOT_5 ' ,
30683067 ];
30693068
3069+ /**
3070+ * Get an array of three strings:
3071+ * - declaration of zend_string, if needed, or empty otherwise
3072+ * - usage of that zend_string, or usage with ZSTR_KNOWN()
3073+ * - freeing the zend_string, if needed
3074+ *
3075+ * @param string $varName
3076+ * @param string $strContent
3077+ * @param ?int $minPHPCompatibility
3078+ * @param bool $interned
3079+ * @return string[]
3080+ */
3081+ public static function getString (
3082+ string $ varName ,
3083+ string $ content ,
3084+ ?int $ minPHPCompatibility ,
3085+ bool $ interned = false
3086+ ): array {
3087+ // Generally strings will not be known
3088+ $ initFn = $ interned ? 'zend_string_init_interned ' : 'zend_string_init ' ;
3089+ $ result = [
3090+ "\tzend_string * $ varName = $ initFn( \"$ content \", sizeof( \"$ content \") - 1, 1); \n" ,
3091+ $ varName ,
3092+ "\tzend_string_release( $ varName); \n"
3093+ ];
3094+ // For attribute values that are not freed
3095+ if ($ varName === '' ) {
3096+ $ result [0 ] = "$ initFn( \"$ content \", sizeof( \"$ content \") - 1, 1); \n" ;
3097+ }
3098+ // If not set, use the current latest version
3099+ $ allVersions = ALL_PHP_VERSION_IDS ;
3100+ $ minPhp = $ minPHPCompatibility ?? end ($ allVersions );
3101+ if ($ minPhp < PHP_80_VERSION_ID ) {
3102+ // No known strings in 7.0
3103+ return $ result ;
3104+ }
3105+ $ include = self ::PHP_80_KNOWN ;
3106+ switch ($ minPhp ) {
3107+ case PHP_85_VERSION_ID :
3108+ $ include = array_merge ($ include , self ::PHP_85_KNOWN );
3109+ // Intentional fall through
3110+
3111+ case PHP_84_VERSION_ID :
3112+ $ include = array_merge ($ include , self ::PHP_84_KNOWN );
3113+ // Intentional fall through
3114+
3115+ case PHP_83_VERSION_ID :
3116+ case PHP_82_VERSION_ID :
3117+ $ include = array_merge ($ include , self ::PHP_82_KNOWN );
3118+ // Intentional fall through
3119+
3120+ case PHP_81_VERSION_ID :
3121+ $ include = array_merge ($ include , self ::PHP_81_KNOWN );
3122+ break ;
3123+ }
3124+ if (array_key_exists ($ content , $ include )) {
3125+ $ knownStr = $ include [$ content ];
3126+ return [
3127+ '' ,
3128+ "ZSTR_KNOWN( $ knownStr) " ,
3129+ '' ,
3130+ ];
3131+ }
3132+ return $ result ;
3133+ }
3134+ }
3135+
3136+ class PropertyInfo extends VariableLike
3137+ {
3138+ private /* readonly */ int $ classFlags ;
3139+ public /* readonly */ PropertyName $ name ;
3140+ private /* readonly */ ?Expr $ defaultValue ;
3141+ private /* readonly */ ?string $ defaultValueString ;
3142+ private /* readonly */ bool $ isDocReadonly ;
3143+ private /* readonly */ bool $ isVirtual ;
3144+
30703145 /**
30713146 * @param AttributeInfo[] $attributes
30723147 */
@@ -3147,7 +3222,11 @@ public function getDeclaration(array $allConstInfos): string {
31473222 $ code .= $ defaultValue ->initializeZval ($ zvalName );
31483223 }
31493224
3150- [$ stringInit , $ nameCode , $ stringRelease ] = $ this ->getString ($ propertyName );
3225+ [$ stringInit , $ nameCode , $ stringRelease ] = StringBuilder::getString (
3226+ "property_ {$ propertyName }_name " ,
3227+ $ propertyName ,
3228+ $ this ->phpVersionIdMinimumCompatibility
3229+ );
31513230 $ code .= $ stringInit ;
31523231
31533232 if ($ this ->exposedDocComment ) {
@@ -3182,60 +3261,6 @@ public function getDeclaration(array $allConstInfos): string {
31823261 return $ code ;
31833262 }
31843263
3185- /**
3186- * Get an array of three strings:
3187- * - declaration of zend_string, if needed, or empty otherwise
3188- * - usage of that zend_string, or usage with ZSTR_KNOWN()
3189- * - freeing the zend_string, if needed
3190- *
3191- * @param string $propName
3192- * @return string[]
3193- */
3194- private function getString (string $ propName ): array {
3195- // Generally strings will not be known
3196- $ nameCode = "property_ {$ propName }_name " ;
3197- $ result = [
3198- "\tzend_string * $ nameCode = zend_string_init( \"$ propName \", sizeof( \"$ propName \") - 1, 1); \n" ,
3199- $ nameCode ,
3200- "\tzend_string_release( $ nameCode); \n"
3201- ];
3202- // If not set, use the current latest version
3203- $ allVersions = ALL_PHP_VERSION_IDS ;
3204- $ minPhp = $ this ->phpVersionIdMinimumCompatibility ?? end ($ allVersions );
3205- if ($ minPhp < PHP_80_VERSION_ID ) {
3206- // No known strings in 7.0
3207- return $ result ;
3208- }
3209- $ include = self ::PHP_80_KNOWN ;
3210- switch ($ minPhp ) {
3211- case PHP_85_VERSION_ID :
3212- $ include = array_merge ($ include , self ::PHP_85_KNOWN );
3213- // Intentional fall through
3214-
3215- case PHP_84_VERSION_ID :
3216- $ include = array_merge ($ include , self ::PHP_84_KNOWN );
3217- // Intentional fall through
3218-
3219- case PHP_83_VERSION_ID :
3220- case PHP_82_VERSION_ID :
3221- $ include = array_merge ($ include , self ::PHP_82_KNOWN );
3222- // Intentional fall through
3223-
3224- case PHP_81_VERSION_ID :
3225- $ include = array_merge ($ include , self ::PHP_81_KNOWN );
3226- break ;
3227- }
3228- if (array_key_exists ($ propName , $ include )) {
3229- $ knownStr = $ include [$ propName ];
3230- return [
3231- '' ,
3232- "ZSTR_KNOWN( $ knownStr) " ,
3233- '' ,
3234- ];
3235- }
3236- return $ result ;
3237- }
3238-
32393264 /**
32403265 * @return array<int, string[]>
32413266 */
@@ -3326,40 +3351,52 @@ public function __construct(string $class, array $args) {
33263351
33273352 /** @param array<string, ConstInfo> $allConstInfos */
33283353 public function generateCode (string $ invocation , string $ nameSuffix , array $ allConstInfos , ?int $ phpVersionIdMinimumCompatibility ): string {
3329- $ php82MinimumCompatibility = $ phpVersionIdMinimumCompatibility === null || $ phpVersionIdMinimumCompatibility >= PHP_82_VERSION_ID ;
3330- $ php84MinimumCompatibility = $ phpVersionIdMinimumCompatibility === null || $ phpVersionIdMinimumCompatibility >= PHP_84_VERSION_ID ;
3331- /* see ZEND_KNOWN_STRINGS in Zend/strings.h */
3332- $ knowns = [
3333- "message " => "ZEND_STR_MESSAGE " ,
3334- ];
3335- if ($ php82MinimumCompatibility ) {
3336- $ knowns ["SensitiveParameter " ] = "ZEND_STR_SENSITIVEPARAMETER " ;
3337- }
3338- if ($ php84MinimumCompatibility ) {
3339- $ knowns ["Deprecated " ] = "ZEND_STR_DEPRECATED_CAPITALIZED " ;
3340- $ knowns ["since " ] = "ZEND_STR_SINCE " ;
3341- }
3342-
3343- $ code = "\n" ;
33443354 $ escapedAttributeName = strtr ($ this ->class , '\\' , '_ ' );
3345- if (isset ($ knowns [$ escapedAttributeName ])) {
3346- $ code .= "\t" . ($ this ->args ? "zend_attribute *attribute_ {$ escapedAttributeName }_ $ nameSuffix = " : "" ) . "$ invocation, ZSTR_KNOWN( {$ knowns [$ escapedAttributeName ]}), " . count ($ this ->args ) . "); \n" ;
3347- } else {
3348- $ code .= "\tzend_string *attribute_name_ {$ escapedAttributeName }_ $ nameSuffix = zend_string_init_interned( \"" . addcslashes ($ this ->class , "\\" ) . "\", sizeof( \"" . addcslashes ($ this ->class , "\\" ) . "\") - 1, 1); \n" ;
3349- $ code .= "\t" . ($ this ->args ? "zend_attribute *attribute_ {$ escapedAttributeName }_ $ nameSuffix = " : "" ) . "$ invocation, attribute_name_ {$ escapedAttributeName }_ $ nameSuffix, " . count ($ this ->args ) . "); \n" ;
3350- $ code .= "\tzend_string_release(attribute_name_ {$ escapedAttributeName }_ $ nameSuffix); \n" ;
3351- }
3355+ [$ stringInit , $ nameCode , $ stringRelease ] = StringBuilder::getString (
3356+ "attribute_name_ {$ escapedAttributeName }_ $ nameSuffix " ,
3357+ addcslashes ($ this ->class , "\\" ),
3358+ $ phpVersionIdMinimumCompatibility ,
3359+ true
3360+ );
3361+ $ code = "\n" ;
3362+ $ code .= $ stringInit ;
3363+ $ code .= "\t" . ($ this ->args ? "zend_attribute *attribute_ {$ escapedAttributeName }_ $ nameSuffix = " : "" ) . "$ invocation, $ nameCode, " . count ($ this ->args ) . "); \n" ;
3364+ $ code .= $ stringRelease ;
3365+
33523366 foreach ($ this ->args as $ i => $ arg ) {
3353- $ value = EvaluatedValue::createFromExpression ($ arg ->value , null , null , $ allConstInfos );
3354- $ zvalName = "attribute_ {$ escapedAttributeName }_ {$ nameSuffix }_arg $ i " ;
3355- $ code .= $ value ->initializeZval ($ zvalName );
3356- $ code .= "\tZVAL_COPY_VALUE(&attribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].value, & $ zvalName); \n" ;
3367+ $ initValue = '' ;
3368+ if ($ arg ->value instanceof Node \Scalar \String_) {
3369+ $ strVal = $ arg ->value ->value ;
3370+ [$ strInit , $ strUse , $ strRelease ] = StringBuilder::getString (
3371+ 'unused ' ,
3372+ $ strVal ,
3373+ $ phpVersionIdMinimumCompatibility
3374+ );
3375+ if ($ strInit === '' ) {
3376+ $ initValue = "\tZVAL_STR(&attribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].value, $ strUse); \n" ;
3377+ }
3378+ }
3379+ if ($ initValue === '' ) {
3380+ $ value = EvaluatedValue::createFromExpression ($ arg ->value , null , null , $ allConstInfos );
3381+ $ zvalName = "attribute_ {$ escapedAttributeName }_ {$ nameSuffix }_arg $ i " ;
3382+ $ code .= $ value ->initializeZval ($ zvalName );
3383+ $ code .= "\tZVAL_COPY_VALUE(&attribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].value, & $ zvalName); \n" ;
3384+ } else {
3385+ $ code .= $ initValue ;
3386+ }
33573387 if ($ arg ->name ) {
3358- if (isset ($ knowns [$ arg ->name ->name ])) {
3359- $ code .= "\tattribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].name = ZSTR_KNOWN( {$ knowns [$ arg ->name ->name ]}); \n" ;
3388+ [$ stringInit , $ nameCode , $ stringRelease ] = StringBuilder::getString (
3389+ "" ,
3390+ $ arg ->name ->name ,
3391+ $ phpVersionIdMinimumCompatibility ,
3392+ true
3393+ );
3394+ if ($ stringInit === '' ) {
3395+ $ nameCode .= "; \n" ;
33603396 } else {
3361- $ code .= "\t attribute_ { $ escapedAttributeName } _ { $ nameSuffix } ->args[ $ i ].name = zend_string_init_interned( \"{ $ arg -> name -> name }\" , sizeof( \"{ $ arg -> name -> name }\" ) - 1, 1); \n" ;
3397+ $ nameCode = $ stringInit ;
33623398 }
3399+ $ code .= "\tattribute_ {$ escapedAttributeName }_ {$ nameSuffix }->args[ $ i].name = $ nameCode " ;
33633400 }
33643401 }
33653402 return $ code ;
0 commit comments