Total Complexity | 50 |
Total Lines | 308 |
Duplicated Lines | 0 % |
Changes | 5 | ||
Bugs | 0 | Features | 0 |
Complex classes like FileCacheReader 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 FileCacheReader, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
32 | class FileCacheReader implements Reader, ReaderWithConstantsAnnotations |
||
|
|||
33 | { |
||
34 | /** |
||
35 | * @var Reader |
||
36 | */ |
||
37 | private $reader; |
||
38 | |||
39 | /** |
||
40 | * @var string |
||
41 | */ |
||
42 | private $dir; |
||
43 | |||
44 | /** |
||
45 | * @var bool |
||
46 | */ |
||
47 | private $debug; |
||
48 | |||
49 | /** |
||
50 | * @var array |
||
51 | */ |
||
52 | private $loadedAnnotations = []; |
||
53 | |||
54 | /** |
||
55 | * @var array |
||
56 | */ |
||
57 | private $classNameHashes = []; |
||
58 | |||
59 | /** |
||
60 | * @var int |
||
61 | */ |
||
62 | private $umask; |
||
63 | |||
64 | /** |
||
65 | * Constructor. |
||
66 | * |
||
67 | * @param Reader $reader |
||
68 | * @param string $cacheDir |
||
69 | * @param boolean $debug |
||
70 | * |
||
71 | * @throws \InvalidArgumentException |
||
72 | */ |
||
73 | public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002) |
||
74 | { |
||
75 | if ( ! is_int($umask)) { |
||
76 | throw new \InvalidArgumentException(sprintf( |
||
77 | 'The parameter umask must be an integer, was: %s', |
||
78 | gettype($umask) |
||
79 | )); |
||
80 | } |
||
81 | |||
82 | $this->reader = $reader; |
||
83 | $this->umask = $umask; |
||
84 | |||
85 | if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777 & (~$this->umask), true)) { |
||
86 | throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $cacheDir)); |
||
87 | } |
||
88 | |||
89 | $this->dir = rtrim($cacheDir, '\\/'); |
||
90 | $this->debug = $debug; |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * {@inheritDoc} |
||
95 | */ |
||
96 | public function getClassAnnotations(\ReflectionClass $class) |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * {@inheritDoc} |
||
129 | */ |
||
130 | public function getPropertyAnnotations(\ReflectionProperty $property) |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * {@inheritDoc} |
||
164 | */ |
||
165 | public function getConstantAnnotations(\ReflectionClassConstant $constant): array |
||
166 | { |
||
167 | $class = $constant->getDeclaringClass(); |
||
168 | if ( ! isset($this->classNameHashes[$class->name])) { |
||
169 | $this->classNameHashes[$class->name] = sha1($class->name); |
||
170 | } |
||
171 | $key = $this->classNameHashes[$class->name].'::'.$constant->getName(); |
||
172 | |||
173 | if (isset($this->loadedAnnotations[$key])) { |
||
174 | return $this->loadedAnnotations[$key]; |
||
175 | } |
||
176 | |||
177 | $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; |
||
178 | if (!is_file($path)) { |
||
179 | $annot = $this->reader->getConstantAnnotations($constant); |
||
180 | $this->saveCacheFile($path, $annot); |
||
181 | return $this->loadedAnnotations[$key] = $annot; |
||
182 | } |
||
183 | |||
184 | if ($this->debug |
||
185 | && (false !== $filename = $class->getFilename()) |
||
186 | && filemtime($path) < filemtime($filename)) { |
||
187 | @unlink($path); |
||
188 | |||
189 | $annot = $this->reader->getConstantAnnotations($constant); |
||
190 | $this->saveCacheFile($path, $annot); |
||
191 | return $this->loadedAnnotations[$key] = $annot; |
||
192 | } |
||
193 | |||
194 | return $this->loadedAnnotations[$key] = include $path; |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * {@inheritDoc} |
||
199 | */ |
||
200 | public function getMethodAnnotations(\ReflectionMethod $method) |
||
201 | { |
||
202 | $class = $method->getDeclaringClass(); |
||
203 | if ( ! isset($this->classNameHashes[$class->name])) { |
||
204 | $this->classNameHashes[$class->name] = sha1($class->name); |
||
205 | } |
||
206 | $key = $this->classNameHashes[$class->name].'#'.$method->getName(); |
||
207 | |||
208 | if (isset($this->loadedAnnotations[$key])) { |
||
209 | return $this->loadedAnnotations[$key]; |
||
210 | } |
||
211 | |||
212 | $path = $this->dir.'/'.strtr($key, '\\', '-').'.cache.php'; |
||
213 | if (!is_file($path)) { |
||
214 | $annot = $this->reader->getMethodAnnotations($method); |
||
215 | $this->saveCacheFile($path, $annot); |
||
216 | return $this->loadedAnnotations[$key] = $annot; |
||
217 | } |
||
218 | |||
219 | if ($this->debug |
||
220 | && (false !== $filename = $class->getFilename()) |
||
221 | && filemtime($path) < filemtime($filename)) { |
||
222 | @unlink($path); |
||
223 | |||
224 | $annot = $this->reader->getMethodAnnotations($method); |
||
225 | $this->saveCacheFile($path, $annot); |
||
226 | return $this->loadedAnnotations[$key] = $annot; |
||
227 | } |
||
228 | |||
229 | return $this->loadedAnnotations[$key] = include $path; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Saves the cache file. |
||
234 | * |
||
235 | * @param string $path |
||
236 | * @param mixed $data |
||
237 | * |
||
238 | * @return void |
||
239 | */ |
||
240 | private function saveCacheFile($path, $data) |
||
241 | { |
||
242 | if (!is_writable($this->dir)) { |
||
243 | throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable. Both, the webserver and the console user need access. You can manage access rights for multiple users with "chmod +a". If your system does not support this, check out the acl package.', $this->dir)); |
||
244 | } |
||
245 | |||
246 | $tempfile = tempnam($this->dir, uniqid('', true)); |
||
247 | |||
248 | if (false === $tempfile) { |
||
249 | throw new \RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir)); |
||
250 | } |
||
251 | |||
252 | @chmod($tempfile, 0666 & (~$this->umask)); |
||
253 | |||
254 | $written = file_put_contents($tempfile, '<?php return unserialize('.var_export(serialize($data), true).');'); |
||
255 | |||
256 | if (false === $written) { |
||
257 | throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile)); |
||
258 | } |
||
259 | |||
260 | @chmod($tempfile, 0666 & (~$this->umask)); |
||
261 | |||
262 | if (false === rename($tempfile, $path)) { |
||
263 | @unlink($tempfile); |
||
264 | throw new \RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path)); |
||
265 | } |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * {@inheritDoc} |
||
270 | */ |
||
271 | public function getClassAnnotation(\ReflectionClass $class, $annotationName) |
||
272 | { |
||
273 | $annotations = $this->getClassAnnotations($class); |
||
274 | |||
275 | foreach ($annotations as $annotation) { |
||
276 | if ($annotation instanceof $annotationName) { |
||
277 | return $annotation; |
||
278 | } |
||
279 | } |
||
280 | |||
281 | return null; |
||
282 | } |
||
283 | |||
284 | /** |
||
285 | * {@inheritDoc} |
||
286 | */ |
||
287 | public function getMethodAnnotation(\ReflectionMethod $method, $annotationName) |
||
288 | { |
||
289 | $annotations = $this->getMethodAnnotations($method); |
||
290 | |||
291 | foreach ($annotations as $annotation) { |
||
292 | if ($annotation instanceof $annotationName) { |
||
293 | return $annotation; |
||
294 | } |
||
295 | } |
||
296 | |||
297 | return null; |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * {@inheritDoc} |
||
302 | */ |
||
303 | public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName) |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * {@inheritDoc} |
||
318 | */ |
||
319 | public function getConstantAnnotation(\ReflectionClassConstant $constant, $annotationName) |
||
320 | { |
||
321 | $annotations = $this->getConstantAnnotations($constant); |
||
322 | |||
323 | foreach ($annotations as $annotation) { |
||
324 | if ($annotation instanceof $annotationName) { |
||
325 | return $annotation; |
||
326 | } |
||
327 | } |
||
328 | |||
329 | return null; |
||
330 | } |
||
331 | |||
332 | /** |
||
333 | * Clears loaded annotations. |
||
334 | * |
||
335 | * @return void |
||
336 | */ |
||
337 | public function clearLoadedAnnotations() |
||
340 | } |
||
341 | } |
||
342 |
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.