Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like autoptimizeScripts 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 autoptimizeScripts, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
4 | class autoptimizeScripts extends autoptimizeBase { |
||
5 | private $scripts = array(); |
||
6 | private $dontmove = array('document.write','html5.js','show_ads.js','google_ad','blogcatalog.com/w','tweetmeme.com/i','mybloglog.com/','histats.com/js','ads.smowtion.com/ad.js','statcounter.com/counter/counter.js','widgets.amung.us','ws.amazon.com/widgets','media.fastclick.net','/ads/','comment-form-quicktags/quicktags.php','edToolbar','intensedebate.com','scripts.chitika.net/','_gaq.push','jotform.com/','admin-bar.min.js','GoogleAnalyticsObject','plupload.full.min.js','syntaxhighlighter','adsbygoogle','gist.github.com','_stq','nonce','post_id','data-noptimize'); |
||
7 | private $domove = array('gaJsHost','load_cmc','jd.gallery.transitions.js','swfobject.embedSWF(','tiny_mce.js','tinyMCEPreInit.go'); |
||
8 | private $domovelast = array('addthis.com','/afsonline/show_afs_search.js','disqus.js','networkedblogs.com/getnetworkwidget','infolinks.com/js/','jd.gallery.js.php','jd.gallery.transitions.js','swfobject.embedSWF(','linkwithin.com/widget.js','tiny_mce.js','tinyMCEPreInit.go'); |
||
9 | private $trycatch = false; |
||
10 | private $alreadyminified = false; |
||
11 | private $forcehead = true; |
||
12 | private $include_inline = false; |
||
13 | private $jscode = ''; |
||
14 | private $url = ''; |
||
15 | private $move = array('first' => array(), 'last' => array()); |
||
16 | private $restofcontent = ''; |
||
17 | private $md5hash = ''; |
||
18 | private $whitelist = ''; |
||
19 | private $jsremovables = array(); |
||
20 | private $inject_min_late = ''; |
||
21 | |||
22 | //Reads the page and collects script tags |
||
23 | public function read($options) { |
||
211 | |||
212 | //Joins and optimizes JS |
||
213 | public function minify() { |
||
214 | foreach($this->scripts as $script) { |
||
215 | if(preg_match('#^INLINE;#',$script)) { |
||
216 | //Inline script |
||
217 | $script = preg_replace('#^INLINE;#','',$script); |
||
218 | $script = rtrim( $script, ";\n\t\r" ) . ';'; |
||
219 | //Add try-catch? |
||
220 | if($this->trycatch) { |
||
221 | $script = 'try{'.$script.'}catch(e){}'; |
||
222 | } |
||
223 | $tmpscript = apply_filters( 'autoptimize_js_individual_script', $script, "" ); |
||
224 | if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscript) ) { |
||
225 | $script=$tmpscript; |
||
226 | $this->alreadyminified=true; |
||
227 | } |
||
228 | $this->jscode .= "\n" . $script; |
||
229 | } else { |
||
230 | //External script |
||
231 | if($script !== false && file_exists($script) && is_readable($script)) { |
||
232 | $scriptsrc = file_get_contents($script); |
||
233 | $scriptsrc = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$scriptsrc); |
||
234 | $scriptsrc = rtrim($scriptsrc,";\n\t\r").';'; |
||
235 | //Add try-catch? |
||
236 | if($this->trycatch) { |
||
237 | $scriptsrc = 'try{'.$scriptsrc.'}catch(e){}'; |
||
238 | } |
||
239 | $tmpscriptsrc = apply_filters( 'autoptimize_js_individual_script', $scriptsrc, $script ); |
||
240 | View Code Duplication | if ( has_filter('autoptimize_js_individual_script') && !empty($tmpscriptsrc) ) { |
|
241 | $scriptsrc=$tmpscriptsrc; |
||
242 | $this->alreadyminified=true; |
||
243 | } else if ($this->can_inject_late($script)) { |
||
244 | $scriptsrc="/*!%%INJECTLATER%%".base64_encode($script)."|".md5($scriptsrc)."%%INJECTLATER%%*/"; |
||
245 | } |
||
246 | $this->jscode .= "\n".$scriptsrc; |
||
247 | }/*else{ |
||
248 | //Couldn't read JS. Maybe getpath isn't working? |
||
249 | }*/ |
||
250 | } |
||
251 | } |
||
252 | |||
253 | //Check for already-minified code |
||
254 | $this->md5hash = md5($this->jscode); |
||
255 | $ccheck = new autoptimizeCache($this->md5hash,'js'); |
||
256 | if($ccheck->check()) { |
||
257 | $this->jscode = $ccheck->retrieve(); |
||
258 | return true; |
||
259 | } |
||
260 | unset($ccheck); |
||
261 | |||
262 | //$this->jscode has all the uncompressed code now. |
||
263 | if ($this->alreadyminified!==true) { |
||
264 | if (class_exists('JSMin') && apply_filters( 'autoptimize_js_do_minify' , true)) { |
||
265 | if (@is_callable(array("JSMin","minify"))) { |
||
266 | $tmp_jscode = trim(JSMin::minify($this->jscode)); |
||
267 | if (!empty($tmp_jscode)) { |
||
268 | $this->jscode = $tmp_jscode; |
||
269 | unset($tmp_jscode); |
||
270 | } |
||
271 | $this->jscode = $this->inject_minified($this->jscode); |
||
272 | $this->jscode = apply_filters( 'autoptimize_js_after_minify', $this->jscode ); |
||
273 | return true; |
||
274 | } else { |
||
275 | $this->jscode = $this->inject_minified($this->jscode); |
||
276 | return false; |
||
277 | } |
||
278 | } else { |
||
279 | $this->jscode = $this->inject_minified($this->jscode); |
||
280 | return false; |
||
281 | } |
||
282 | } |
||
283 | return true; |
||
284 | } |
||
285 | |||
286 | //Caches the JS in uncompressed, deflated and gzipped form. |
||
287 | public function cache() { |
||
296 | |||
297 | // Returns the content |
||
298 | public function getcontent() { |
||
340 | |||
341 | // Checks against the white- and blacklists |
||
342 | private function ismergeable($tag) { |
||
376 | |||
377 | // Checks againstt the blacklist |
||
378 | private function ismovable($tag) { |
||
404 | |||
405 | private function movetolast($tag) { |
||
416 | |||
417 | /** |
||
418 | * Determines wheter a <script> $tag should be aggregated or not. |
||
419 | * |
||
420 | * We consider these as "aggregation-safe" currently: |
||
421 | * - script tags without a `type` attribute |
||
422 | * - script tags with an explicit `type` of `text/javascript`, 'text/ecmascript', |
||
423 | * 'application/javascript' or 'application/ecmascript' |
||
424 | * |
||
425 | * Everything else should return false. |
||
426 | * |
||
427 | * @param string $tag |
||
428 | * @return bool |
||
429 | * |
||
430 | * original function by https://github.com/zytzagoo/ on his AO fork, thanks Tomas! |
||
431 | */ |
||
432 | public function should_aggregate($tag) { |
||
442 | |||
443 | /** |
||
444 | * Determines wheter a <script> $tag can be excluded from minification (as already minified) based on: |
||
445 | * - inject_min_late being active |
||
446 | * - filename ending in `min.js` |
||
447 | * - filename matching `js/jquery/jquery.js` (wordpress core jquery, is minified) |
||
448 | * - filename matching one passed in the consider minified filter |
||
449 | * |
||
450 | * @param string $jsPath |
||
451 | * @return bool |
||
452 | */ |
||
453 | private function can_inject_late($jsPath) { |
||
466 | } |
||
467 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..