@@ -40,6 +40,9 @@ class Resetter implements ResetterInterface
40
40
/** @var array */
41
41
private readonly array $ classList ;
42
42
43
+ /** @var array */
44
+ private array $ sortedClassListsByClass = [];
45
+
43
46
/**
44
47
* @param ComponentRegistrarInterface|null $componentRegistrar
45
48
* @param array $classList
@@ -172,11 +175,67 @@ private function resetStateWithReflection(object $instance)
172
175
$ instance ->{self ::RESET_STATE_METHOD }();
173
176
return ;
174
177
}
175
- foreach ($ this ->classList as $ className => $ value ) {
176
- if ($ instance instanceof $ className ) {
177
- $ this ->resetStateWithReflectionByClassName ($ instance , $ className );
178
+ $ className = get_class ($ instance );
179
+ if (!array_key_exists ($ className , $ this ->sortedClassListsByClass )) {
180
+ $ temporaryClassList = [];
181
+ foreach ($ this ->classList as $ key => $ value ) {
182
+ if ($ instance instanceof $ key ) {
183
+ $ temporaryClassList [] = $ key ;
184
+ }
178
185
}
186
+ $ this ->sortClasses ($ temporaryClassList );
187
+ $ this ->sortedClassListsByClass [$ className ] = $ temporaryClassList ;
188
+ }
189
+ foreach ($ this ->sortedClassListsByClass [$ className ] as $ currentClassName ) {
190
+ $ this ->resetStateWithReflectionByClassName ($ instance , $ currentClassName );
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Sorts an array of strings that are class names and interface names
196
+ *
197
+ * Note: This sorting algorithm only takes arrays that are keyed by contiguous numbers starting at zero.
198
+ * Note: This sorting algorithm works with comparators that return false on unrelated items.
199
+ *
200
+ * @param array $array
201
+ * @return void
202
+ */
203
+ private function sortClasses (array &$ array ) : void
204
+ {
205
+ $ i = 0 ;
206
+ $ count = count ($ array );
207
+ while ($ i + 1 < $ count ) {
208
+ for ($ j = $ i + 1 ; $ j < $ count ; $ j ++) {
209
+ if ($ this ->sortClassesComparitor ($ array [$ i ], $ array [$ j ])) {
210
+ $ swapTemp = $ array [$ i ];
211
+ $ array [$ i ] = $ array [$ j ];
212
+ $ array [$ j ] = $ swapTemp ;
213
+ continue 2 ;
214
+ }
215
+ }
216
+ $ i ++;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Comparator for class/interface sorter that returns true if $b should come before $a.
222
+ *
223
+ * @param string $a
224
+ * @param string $b
225
+ * @return bool
226
+ */
227
+ private function sortClassesComparitor (string $ a , string $ b ) : bool
228
+ {
229
+ if (is_a ($ a , $ b , true )) {
230
+ return true ;
231
+ }
232
+ if (is_a ($ b , $ a , true )) {
233
+ return false ;
234
+ }
235
+ if (interface_exists ($ a ) && class_exists ($ b )) {
236
+ return true ; // Note: If they aren't related, classes should come before interfaces
179
237
}
238
+ return false ; // No relation
180
239
}
181
240
182
241
/**
0 commit comments