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
@@ -232,6 +236,43 @@ public function render(AbstractRenderer $renderer): string
232
236
: $ renderer ->render ();
233
237
}
234
238
239
+ /**
240
+ * Claim this class is all set.
241
+ *
242
+ * Properties will be propagated to other classes. You must re-call
243
+ * this method after any property changed before doing calculation.
244
+ *
245
+ * @return self
246
+ */
247
+ private function finalize (): self
248
+ {
249
+ if ($ this ->isCacheDirty ) {
250
+ $ this ->resetCachedResults ();
251
+
252
+ $ this ->sequenceMatcher
253
+ ->setOptions ($ this ->options )
254
+ ->setSequences ($ this ->old , $ this ->new );
255
+ }
256
+
257
+ return $ this ;
258
+ }
259
+
260
+ /**
261
+ * Reset cached results.
262
+ *
263
+ * @return self
264
+ */
265
+ private function resetCachedResults (): self
266
+ {
267
+ foreach (static ::CACHED_PROPERTIES as $ property => $ value ) {
268
+ $ this ->$ property = $ value ;
269
+ }
270
+
271
+ $ this ->isCacheDirty = false ;
272
+
273
+ return $ this ;
274
+ }
275
+
235
276
/**
236
277
* The work horse of getA() and getB().
237
278
*
0 commit comments