17
17
*/
18
18
final class Diff
19
19
{
20
+ /**
21
+ * @var array cached properties and their default values
22
+ */
23
+ private const CACHED_PROPERTIES = [
24
+ 'groupedCodes ' => null ,
25
+ ];
26
+
20
27
/**
21
28
* @var array array of the options that have been applied for generating the diff
22
29
*/
@@ -32,6 +39,11 @@ final class Diff
32
39
*/
33
40
private $ new = [];
34
41
42
+ /**
43
+ * @var bool is any of cached properties dirty?
44
+ */
45
+ private $ isCacheDirty = true ;
46
+
35
47
/**
36
48
* @var null|SequenceMatcher the sequence matcher
37
49
*/
@@ -94,8 +106,7 @@ public function setOld(array $old): self
94
106
{
95
107
if ($ this ->old !== $ old ) {
96
108
$ this ->old = $ old ;
97
- $ this ->sequenceMatcher ->setSeq1 ($ old );
98
- $ this ->resetCachedResults ();
109
+ $ this ->isCacheDirty = true ;
99
110
}
100
111
101
112
return $ this ;
@@ -112,8 +123,7 @@ public function setNew(array $new): self
112
123
{
113
124
if ($ this ->new !== $ new ) {
114
125
$ this ->new = $ new ;
115
- $ this ->sequenceMatcher ->setSeq2 ($ new );
116
- $ this ->resetCachedResults ();
126
+ $ this ->isCacheDirty = true ;
117
127
}
118
128
119
129
return $ this ;
@@ -128,10 +138,12 @@ public function setNew(array $new): self
128
138
*/
129
139
public function setOptions (array $ options ): self
130
140
{
131
- $ this -> options = $ options + static ::$ defaultOptions ;
141
+ $ mergedOptions = $ options + static ::$ defaultOptions ;
132
142
133
- $ this ->sequenceMatcher ->setOptions ($ this ->options );
134
- $ this ->resetCachedResults ();
143
+ if ($ this ->options !== $ mergedOptions ) {
144
+ $ this ->options = $ mergedOptions ;
145
+ $ this ->isCacheDirty = true ;
146
+ }
135
147
136
148
return $ this ;
137
149
}
@@ -198,22 +210,12 @@ public static function getInstance(): self
198
210
*/
199
211
public function getGroupedOpcodes (): array
200
212
{
213
+ $ this ->finalize ();
214
+
201
215
return $ this ->groupedCodes = $ this ->groupedCodes ??
202
216
$ this ->sequenceMatcher ->getGroupedOpcodes ($ this ->options ['context ' ]);
203
217
}
204
218
205
- /**
206
- * Reset cached results.
207
- *
208
- * @return self
209
- */
210
- public function resetCachedResults (): self
211
- {
212
- $ this ->groupedCodes = null ;
213
-
214
- return $ this ;
215
- }
216
-
217
219
/**
218
220
* Render a diff using the supplied rendering class and return it.
219
221
*
@@ -223,6 +225,8 @@ public function resetCachedResults(): self
223
225
*/
224
226
public function render (AbstractRenderer $ renderer ): string
225
227
{
228
+ $ this ->finalize ();
229
+
226
230
$ renderer ->setDiff ($ this );
227
231
228
232
// the "no difference" situation may happen frequently
@@ -311,6 +315,43 @@ public function getB(int $start = 0, ?int $end = null): array
311
315
return $ this ->getNew ($ start , $ end );
312
316
}
313
317
318
+ /**
319
+ * Claim this class is all set.
320
+ *
321
+ * Properties will be propagated to other classes. You must re-call
322
+ * this method after any property changed before doing calculation.
323
+ *
324
+ * @return self
325
+ */
326
+ private function finalize (): self
327
+ {
328
+ if ($ this ->isCacheDirty ) {
329
+ $ this ->resetCachedResults ();
330
+
331
+ $ this ->sequenceMatcher
332
+ ->setOptions ($ this ->options )
333
+ ->setSequences ($ this ->old , $ this ->new );
334
+ }
335
+
336
+ return $ this ;
337
+ }
338
+
339
+ /**
340
+ * Reset cached results.
341
+ *
342
+ * @return self
343
+ */
344
+ private function resetCachedResults (): self
345
+ {
346
+ foreach (static ::CACHED_PROPERTIES as $ property => $ value ) {
347
+ $ this ->$ property = $ value ;
348
+ }
349
+
350
+ $ this ->isCacheDirty = false ;
351
+
352
+ return $ this ;
353
+ }
354
+
314
355
/**
315
356
* The work horse of getA() and getB().
316
357
*
0 commit comments