@@ -118,30 +118,70 @@ protected function processMemberVar(File $phpcsFile, $stackPtr)
118
118
$ phpcsFile ->addError ($ error , $ stackPtr , 'ScopeMissing ' , $ data );
119
119
}
120
120
121
+ /*
122
+ * Note: per PSR-PER section 4.6, the order should be:
123
+ * - Inheritance modifier: `abstract` or `final`.
124
+ * - Visibility modifier: `public`, `protected`, or `private`.
125
+ * - Scope modifier: `static`.
126
+ * - Mutation modifier: `readonly`.
127
+ * - Type declaration.
128
+ * - Name.
129
+ *
130
+ * Ref: https://www.php-fig.org/per/coding-style/#46-modifier-keywords
131
+ *
132
+ * At this time (PHP 8.2), inheritance modifiers cannot be applied to properties and
133
+ * the `static` and `readonly` modifiers are mutually exclusive and cannot be used together.
134
+ *
135
+ * Based on that, the below modifier keyword order checks are sufficient (for now).
136
+ */
137
+
121
138
if ($ propertyInfo ['scope_specified ' ] === true && $ propertyInfo ['is_static ' ] === true ) {
122
139
$ scopePtr = $ phpcsFile ->findPrevious (Tokens::$ scopeModifiers , ($ stackPtr - 1 ));
123
140
$ staticPtr = $ phpcsFile ->findPrevious (T_STATIC , ($ stackPtr - 1 ));
124
- if ($ scopePtr < $ staticPtr ) {
125
- return ;
126
- }
141
+ if ($ scopePtr > $ staticPtr ) {
142
+ $ error = 'The static declaration must come after the visibility declaration ' ;
143
+ $ fix = $ phpcsFile ->addFixableError ($ error , $ stackPtr , 'StaticBeforeVisibility ' );
144
+ if ($ fix === true ) {
145
+ $ phpcsFile ->fixer ->beginChangeset ();
127
146
128
- $ error = ' The static declaration must come after the visibility declaration ' ;
129
- $ fix = $ phpcsFile -> addFixableError ( $ error , $ stackPtr , ' StaticBeforeVisibility ' );
130
- if ( $ fix === true ) {
131
- $ phpcsFile -> fixer -> beginChangeset ();
147
+ for ( $ i = ( $ scopePtr + 1 ); $ scopePtr < $ stackPtr ; $ i ++) {
148
+ if ( $ tokens [ $ i ][ ' code ' ] !== T_WHITESPACE ) {
149
+ break ;
150
+ }
132
151
133
- for ($ i = ($ scopePtr + 1 ); $ scopePtr < $ stackPtr ; $ i ++) {
134
- if ($ tokens [$ i ]['code ' ] !== T_WHITESPACE ) {
135
- break ;
152
+ $ phpcsFile ->fixer ->replaceToken ($ i , '' );
136
153
}
137
154
138
- $ phpcsFile ->fixer ->replaceToken ($ i , '' );
155
+ $ phpcsFile ->fixer ->replaceToken ($ scopePtr , '' );
156
+ $ phpcsFile ->fixer ->addContentBefore ($ staticPtr , $ propertyInfo ['scope ' ].' ' );
157
+
158
+ $ phpcsFile ->fixer ->endChangeset ();
139
159
}
160
+ }
161
+ }//end if
162
+
163
+ if ($ propertyInfo ['scope_specified ' ] === true && $ propertyInfo ['is_readonly ' ] === true ) {
164
+ $ scopePtr = $ phpcsFile ->findPrevious (Tokens::$ scopeModifiers , ($ stackPtr - 1 ));
165
+ $ readonlyPtr = $ phpcsFile ->findPrevious (T_READONLY , ($ stackPtr - 1 ));
166
+ if ($ scopePtr > $ readonlyPtr ) {
167
+ $ error = 'The readonly declaration must come after the visibility declaration ' ;
168
+ $ fix = $ phpcsFile ->addFixableError ($ error , $ stackPtr , 'ReadonlyBeforeVisibility ' );
169
+ if ($ fix === true ) {
170
+ $ phpcsFile ->fixer ->beginChangeset ();
171
+
172
+ for ($ i = ($ scopePtr + 1 ); $ scopePtr < $ stackPtr ; $ i ++) {
173
+ if ($ tokens [$ i ]['code ' ] !== T_WHITESPACE ) {
174
+ break ;
175
+ }
176
+
177
+ $ phpcsFile ->fixer ->replaceToken ($ i , '' );
178
+ }
140
179
141
- $ phpcsFile ->fixer ->replaceToken ($ scopePtr , '' );
142
- $ phpcsFile ->fixer ->addContentBefore ($ staticPtr , $ propertyInfo ['scope ' ].' ' );
180
+ $ phpcsFile ->fixer ->replaceToken ($ scopePtr , '' );
181
+ $ phpcsFile ->fixer ->addContentBefore ($ readonlyPtr , $ propertyInfo ['scope ' ].' ' );
143
182
144
- $ phpcsFile ->fixer ->endChangeset ();
183
+ $ phpcsFile ->fixer ->endChangeset ();
184
+ }
145
185
}
146
186
}//end if
147
187
0 commit comments