Total Complexity | 41 |
Total Lines | 280 |
Duplicated Lines | 0 % |
Changes | 8 | ||
Bugs | 0 | Features | 0 |
Complex classes like CachedReader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CachedReader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | final class CachedReader implements Reader, ReaderWithConstantsAnnotations |
||
|
|||
32 | { |
||
33 | /** |
||
34 | * @var Reader |
||
35 | */ |
||
36 | private $delegate; |
||
37 | |||
38 | /** |
||
39 | * @var Cache |
||
40 | */ |
||
41 | private $cache; |
||
42 | |||
43 | /** |
||
44 | * @var boolean |
||
45 | */ |
||
46 | private $debug; |
||
47 | |||
48 | /** |
||
49 | * @var array |
||
50 | */ |
||
51 | private $loadedAnnotations = []; |
||
52 | |||
53 | /** |
||
54 | * @var int[] |
||
55 | */ |
||
56 | private $loadedFilemtimes = []; |
||
57 | |||
58 | /** |
||
59 | * @param bool $debug |
||
60 | */ |
||
61 | public function __construct(Reader $reader, Cache $cache, $debug = false) |
||
62 | { |
||
63 | $this->delegate = $reader; |
||
64 | $this->cache = $cache; |
||
65 | $this->debug = (boolean) $debug; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * {@inheritDoc} |
||
70 | */ |
||
71 | public function getClassAnnotations(ReflectionClass $class) |
||
72 | { |
||
73 | $cacheKey = $class->getName(); |
||
74 | |||
75 | if (isset($this->loadedAnnotations[$cacheKey])) { |
||
76 | return $this->loadedAnnotations[$cacheKey]; |
||
77 | } |
||
78 | |||
79 | if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { |
||
80 | $annots = $this->delegate->getClassAnnotations($class); |
||
81 | $this->saveToCache($cacheKey, $annots); |
||
82 | } |
||
83 | |||
84 | return $this->loadedAnnotations[$cacheKey] = $annots; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * {@inheritDoc} |
||
89 | */ |
||
90 | public function getClassAnnotation(ReflectionClass $class, $annotationName) |
||
91 | { |
||
92 | foreach ($this->getClassAnnotations($class) as $annot) { |
||
93 | if ($annot instanceof $annotationName) { |
||
94 | return $annot; |
||
95 | } |
||
96 | } |
||
97 | |||
98 | return null; |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * {@inheritDoc} |
||
103 | */ |
||
104 | public function getPropertyAnnotations(\ReflectionProperty $property) |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * {@inheritDoc} |
||
123 | */ |
||
124 | public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * {@inheritDoc} |
||
137 | */ |
||
138 | public function getConstantAnnotations(\ReflectionClassConstant $constant): array |
||
139 | { |
||
140 | $class = $constant->getDeclaringClass(); |
||
141 | $cacheKey = $class->getName().'::'.$constant->getName(); |
||
142 | |||
143 | if (isset($this->loadedAnnotations[$cacheKey])) { |
||
144 | return $this->loadedAnnotations[$cacheKey]; |
||
145 | } |
||
146 | |||
147 | if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { |
||
148 | $annots = $this->delegate->getConstantAnnotations($constant); |
||
149 | $this->saveToCache($cacheKey, $annots); |
||
150 | } |
||
151 | |||
152 | return $this->loadedAnnotations[$cacheKey] = $annots; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * {@inheritDoc} |
||
157 | */ |
||
158 | public function getConstantAnnotation(\ReflectionClassConstant $constant, $annotationName) |
||
159 | { |
||
160 | foreach ($this->getConstantAnnotations($constant) as $annot) { |
||
161 | if ($annot instanceof $annotationName) { |
||
162 | return $annot; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | return null; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * {@inheritDoc} |
||
171 | */ |
||
172 | public function getMethodAnnotations(\ReflectionMethod $method) |
||
173 | { |
||
174 | $class = $method->getDeclaringClass(); |
||
175 | $cacheKey = $class->getName().'#'.$method->getName(); |
||
176 | |||
177 | if (isset($this->loadedAnnotations[$cacheKey])) { |
||
178 | return $this->loadedAnnotations[$cacheKey]; |
||
179 | } |
||
180 | |||
181 | if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) { |
||
182 | $annots = $this->delegate->getMethodAnnotations($method); |
||
183 | $this->saveToCache($cacheKey, $annots); |
||
184 | } |
||
185 | |||
186 | return $this->loadedAnnotations[$cacheKey] = $annots; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * {@inheritDoc} |
||
191 | */ |
||
192 | public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) |
||
193 | { |
||
194 | foreach ($this->getMethodAnnotations($method) as $annot) { |
||
195 | if ($annot instanceof $annotationName) { |
||
196 | return $annot; |
||
197 | } |
||
198 | } |
||
199 | |||
200 | return null; |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Clears loaded annotations. |
||
205 | * |
||
206 | * @return void |
||
207 | */ |
||
208 | public function clearLoadedAnnotations() |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * Fetches a value from the cache. |
||
216 | * |
||
217 | * @param string $cacheKey The cache key. |
||
218 | * |
||
219 | * @return mixed The cached value or false when the value is not in cache. |
||
220 | */ |
||
221 | private function fetchFromCache($cacheKey, ReflectionClass $class) |
||
222 | { |
||
223 | if (($data = $this->cache->fetch($cacheKey)) !== false) { |
||
224 | if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) { |
||
225 | return $data; |
||
226 | } |
||
227 | } |
||
228 | |||
229 | return false; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Saves a value to the cache. |
||
234 | * |
||
235 | * @param string $cacheKey The cache key. |
||
236 | * @param mixed $value The value. |
||
237 | * |
||
238 | * @return void |
||
239 | */ |
||
240 | private function saveToCache($cacheKey, $value) |
||
241 | { |
||
242 | $this->cache->save($cacheKey, $value); |
||
243 | if ($this->debug) { |
||
244 | $this->cache->save('[C]'.$cacheKey, time()); |
||
245 | } |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Checks if the cache is fresh. |
||
250 | * |
||
251 | * @param string $cacheKey |
||
252 | * |
||
253 | * @return boolean |
||
254 | */ |
||
255 | private function isCacheFresh($cacheKey, ReflectionClass $class) |
||
263 | } |
||
264 | |||
265 | /** |
||
266 | * Returns the time the class was last modified, testing traits and parents |
||
267 | * |
||
268 | * @return int |
||
269 | */ |
||
270 | private function getLastModification(ReflectionClass $class) |
||
271 | { |
||
272 | $filename = $class->getFileName(); |
||
273 | |||
274 | if (isset($this->loadedFilemtimes[$filename])) { |
||
275 | return $this->loadedFilemtimes[$filename]; |
||
276 | } |
||
277 | |||
278 | $parent = $class->getParentClass(); |
||
279 | |||
280 | $lastModification = max(array_merge( |
||
281 | [$filename ? filemtime($filename) : 0], |
||
282 | array_map([$this, 'getTraitLastModificationTime'], $class->getTraits()), |
||
283 | array_map([$this, 'getLastModification'], $class->getInterfaces()), |
||
284 | $parent ? [$this->getLastModification($parent)] : [] |
||
285 | )); |
||
286 | |||
287 | assert($lastModification !== false); |
||
288 | |||
289 | return $this->loadedFilemtimes[$filename] = $lastModification; |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * @return int |
||
294 | */ |
||
295 | private function getTraitLastModificationTime(ReflectionClass $reflectionTrait) |
||
311 | } |
||
312 | } |
||
313 |
This interface has been deprecated. The supplier of the interface has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.