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..