Complex classes like CSS 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 CSS, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class CSS extends Minify |
||
19 | { |
||
20 | /** |
||
21 | * @var int |
||
22 | */ |
||
23 | protected $maxImportSize = 5; |
||
24 | |||
25 | /** |
||
26 | * @var string[] |
||
27 | */ |
||
28 | protected $importExtensions = array( |
||
29 | 'gif' => 'data:image/gif', |
||
30 | 'png' => 'data:image/png', |
||
31 | 'jpe' => 'data:image/jpeg', |
||
32 | 'jpg' => 'data:image/jpeg', |
||
33 | 'jpeg' => 'data:image/jpeg', |
||
34 | 'svg' => 'data:image/svg+xml', |
||
35 | 'woff' => 'data:application/x-font-woff', |
||
36 | 'tif' => 'image/tiff', |
||
37 | 'tiff' => 'image/tiff', |
||
38 | 'xbm' => 'image/x-xbitmap', |
||
39 | ); |
||
40 | |||
41 | /** |
||
42 | * Set the maximum size if files to be imported. |
||
43 | * |
||
44 | * Files larger than this size (in kB) will not be imported into the CSS. |
||
45 | * Importing files into the CSS as data-uri will save you some connections, |
||
46 | * but we should only import relatively small decorative images so that our |
||
47 | * CSS file doesn't get too bulky. |
||
48 | * |
||
49 | * @param int $size Size in kB |
||
50 | */ |
||
51 | public function setMaxImportSize($size) |
||
55 | |||
56 | /** |
||
57 | * Set the type of extensions to be imported into the CSS (to save network |
||
58 | * connections). |
||
59 | * Keys of the array should be the file extensions & respective values |
||
60 | * should be the data type. |
||
61 | * |
||
62 | * @param string[] $extensions Array of file extensions |
||
63 | */ |
||
64 | public function setImportExtensions(array $extensions) |
||
68 | |||
69 | /** |
||
70 | * Move any import statements to the top. |
||
71 | * |
||
72 | * @param string $content Nearly finished CSS content |
||
73 | * |
||
74 | * @return string |
||
75 | */ |
||
76 | protected function moveImportsToTop($content) |
||
90 | |||
91 | /** |
||
92 | * Combine CSS from import statements. |
||
93 | * |
||
94 | * @import's will be loaded and their content merged into the original file, |
||
95 | * to save HTTP requests. |
||
96 | * |
||
97 | * @param string $source The file to combine imports for |
||
98 | * @param string $content The CSS content to combine imports for |
||
99 | * @param string[] $parents Parent paths, for circular reference checks |
||
100 | * |
||
101 | * @return string |
||
102 | * |
||
103 | * @throws FileImportException |
||
104 | */ |
||
105 | protected function combineImports($source, $content, $parents) |
||
224 | |||
225 | /** |
||
226 | * Import files into the CSS, base64-ized. |
||
227 | * |
||
228 | * @url(image.jpg) images will be loaded and their content merged into the |
||
229 | * original file, to save HTTP requests. |
||
230 | * |
||
231 | * @param string $source The file to import files for |
||
232 | * @param string $content The CSS content to import files for |
||
233 | * |
||
234 | * @return string |
||
235 | */ |
||
236 | protected function importFiles($source, $content) |
||
237 | { |
||
238 | $extensions = array_keys($this->importExtensions); |
||
239 | $regex = '/url\((["\']?)((?!["\']?data:).*?\.('.implode('|', $extensions).'))\\1\)/i'; |
||
240 | if ($extensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) { |
||
|
|||
241 | $search = array(); |
||
242 | $replace = array(); |
||
243 | |||
244 | // loop the matches |
||
245 | foreach ($matches as $match) { |
||
246 | // get the path for the file that will be imported |
||
247 | $path = $match[2]; |
||
248 | $path = dirname($source).'/'.$path; |
||
249 | $extension = $match[3]; |
||
250 | |||
251 | // only replace the import with the content if we're able to get |
||
252 | // the content of the file, and it's relatively small |
||
253 | if ($this->canImportFile($path) && $this->canImportBySize($path)) { |
||
254 | // grab content && base64-ize |
||
255 | $importContent = $this->load($path); |
||
256 | $importContent = base64_encode($importContent); |
||
257 | |||
258 | // build replacement |
||
259 | $search[] = $match[0]; |
||
260 | $replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')'; |
||
261 | } |
||
262 | } |
||
263 | |||
264 | // replace the import statements |
||
265 | $content = str_replace($search, $replace, $content); |
||
266 | } |
||
267 | |||
268 | return $content; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Minify the data. |
||
273 | * Perform CSS optimizations. |
||
274 | * |
||
275 | * @param string[optional] $path Path to write the data to |
||
276 | * @param string[] $parents Parent paths, for circular reference checks |
||
277 | * |
||
278 | * @return string The minified data |
||
279 | */ |
||
280 | public function execute($path = null, $parents = array()) |
||
328 | |||
329 | /** |
||
330 | * Moving a css file should update all relative urls. |
||
331 | * Relative references (e.g. ../images/image.gif) in a certain css file, |
||
332 | * will have to be updated when a file is being saved at another location |
||
333 | * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper). |
||
334 | * |
||
335 | * @param Converter $converter Relative path converter |
||
336 | * @param string $content The CSS content to update relative urls for |
||
337 | * |
||
338 | * @return string |
||
339 | */ |
||
340 | protected function move(Converter $converter, $content) |
||
441 | |||
442 | /** |
||
443 | * Shorthand hex color codes. |
||
444 | * #FF0000 -> #F00. |
||
445 | * |
||
446 | * @param string $content The CSS content to shorten the hex color codes for |
||
447 | * |
||
448 | * @return string |
||
449 | */ |
||
450 | protected function shortenHex($content) |
||
493 | |||
494 | /** |
||
495 | * Shorten CSS font weights. |
||
496 | * |
||
497 | * @param string $content The CSS content to shorten the font weights for |
||
498 | * |
||
499 | * @return string |
||
500 | */ |
||
501 | protected function shortenFontWeights($content) |
||
514 | |||
515 | /** |
||
516 | * Shorthand 0 values to plain 0, instead of e.g. -0em. |
||
517 | * |
||
518 | * @param string $content The CSS content to shorten the zero values for |
||
519 | * |
||
520 | * @return string |
||
521 | */ |
||
522 | protected function shortenZeroes($content) |
||
572 | |||
573 | /** |
||
574 | * Strip comments from source code. |
||
575 | * |
||
576 | * @param string $content |
||
577 | * |
||
578 | * @return string |
||
579 | */ |
||
580 | protected function stripEmptyTags($content) |
||
584 | |||
585 | /** |
||
586 | * Strip comments from source code. |
||
587 | */ |
||
588 | protected function stripComments() |
||
592 | |||
593 | /** |
||
594 | * Strip whitespace. |
||
595 | * |
||
596 | * @param string $content The CSS content to strip the whitespace for |
||
597 | * |
||
598 | * @return string |
||
599 | */ |
||
600 | protected function stripWhitespace($content) |
||
626 | |||
627 | /** |
||
628 | * Check if file is small enough to be imported. |
||
629 | * |
||
630 | * @param string $path The path to the file |
||
631 | * |
||
632 | * @return bool |
||
633 | */ |
||
634 | protected function canImportBySize($path) |
||
638 | |||
639 | /** |
||
640 | * Check if file a file can be imported, going by the path. |
||
641 | * |
||
642 | * @param string $path |
||
643 | * |
||
644 | * @return bool |
||
645 | */ |
||
646 | protected function canImportByPath($path) |
||
650 | } |
||
651 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.