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 SemRush 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 SemRush, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class SemRush extends SEOstats |
||
| 20 | { |
||
| 21 | 30 | public static function getDBs() |
|
| 22 | { |
||
| 23 | return array( |
||
| 24 | 30 | "au", # Google.com.au (Australia) |
|
| 25 | 30 | "br", # Google.com.br (Brazil) |
|
| 26 | 30 | "ca", # Google.ca (Canada) |
|
| 27 | 30 | "de", # Google.de (Germany) |
|
| 28 | 30 | "es", # Google.es (Spain) |
|
| 29 | 30 | "fr", # Google.fr (France) |
|
| 30 | 30 | "it", # Google.it (Italy) |
|
| 31 | 30 | "ru", # Google.ru (Russia) |
|
| 32 | 30 | "uk", # Google.co.uk (United Kingdom) |
|
| 33 | 30 | 'us', # Google.com (United States) |
|
| 34 | "us.bing" # Bing.com |
||
| 35 | 30 | ); |
|
| 36 | } |
||
| 37 | |||
| 38 | 1 | public static function getParams() |
|
| 39 | { |
||
| 40 | return array( |
||
| 41 | "DomainReports" => array( |
||
| 42 | 1 | "Ac" => "Estimated expenses the site has for advertising in Ads (per month).", |
|
| 43 | 1 | "Ad" => "Number of Keywords this site has in the TOP20 Ads results.", |
|
| 44 | 1 | "At" => "Estimated number of visitors coming from Ads (per month).", |
|
| 45 | 1 | "Dn" => "The requested site name.", |
|
| 46 | 1 | "Dt" => "The date when the report data was computed (formatted as YYYYmmdd).", |
|
| 47 | 1 | "Np" => "The number of keywords for which the site is displayed in search results next to the analyzed site.", |
|
| 48 | 1 | "Oa" => "Estimated number of potential ad/traffic buyers.", |
|
| 49 | 1 | "Oc" => "Estimated cost of purchasing the same number of visitors through Ads.", |
|
| 50 | 1 | "Oo" => "Estimated number of competitors in organic search.", |
|
| 51 | 1 | "Or" => "Number of Keywords this site has in the TOP20 organic results.", |
|
| 52 | 1 | "Ot" => "Estimated number of visitors coming from the first 20 search results (per month).", |
|
| 53 | "Rk" => "The SEMRush Rank (rating of sites by the number of visitors coming from the first 20 search results)." |
||
| 54 | 1 | ), |
|
| 55 | "OrganicKeywordReports" => array( |
||
| 56 | 1 | "Co" => "Competition of advertisers for that term (the higher the number - the greater the competition).", |
|
| 57 | 1 | "Cp" => "Average price of a click on an Ad for this search query (in U.S. dollars).", |
|
| 58 | 1 | "Nr" => "The number of search results - how many results does the search engine return for this query.", |
|
| 59 | 1 | "Nq" => "Average number of queries for the keyword per month (for the corresponding local version of search engine).", |
|
| 60 | 1 | "Ph" => "The search query the site has within the first 20 search results.", |
|
| 61 | 1 | "Po" => "The site's position for the search query (at the moment of data collection).", |
|
| 62 | 1 | "Pp" => "The site's position for the search query (at the time of prior data collection).", |
|
| 63 | 1 | "Tc" => "The estimated value of the organic traffic generated by the query as compared to the cost of purchasing the same volume of traffic through Ads.", |
|
| 64 | 1 | "Tr" => "The ratio comparing the number of visitors coming to the site from this search request to all visitors to the site from search results.", |
|
| 65 | "Ur" => "URL of a page on the site displayed in search results for this query (landing page)." |
||
| 66 | 1 | ) |
|
| 67 | 1 | ); |
|
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Returns the SEMRush main report data. |
||
| 72 | * (Only main report is public available.) |
||
| 73 | * |
||
| 74 | * @access public |
||
| 75 | * @param url string Domain name only, eg. "ebay.com" (/wo quotes). |
||
| 76 | * @param db string Optional: The database to use. Valid values are: |
||
| 77 | * au, br, ca, de, es, fr, it, ru, uk, us, us.bing (us is default) |
||
| 78 | * @return array Returns an array containing the main report data. |
||
| 79 | * @link http://www.semrush.com/api.html |
||
| 80 | */ |
||
| 81 | 6 | public static function getDomainRank($url = false, $db = false) |
|
| 87 | |||
| 88 | 6 | public static function getDomainRankHistory($url = false, $db = false) |
|
| 94 | |||
| 95 | 4 | public static function getOrganicKeywords($url = false, $db = false) |
|
| 99 | |||
| 100 | 4 | public static function getCompetitors($url = false, $db = false) |
|
| 104 | |||
| 105 | 10 | public static function getDomainGraph($reportType = 1, $url = false, $db = false, $w = 400, $h = 300, $lc = 'e43011', $dc = 'e43011', $lang = 'en', $html = true) |
|
| 122 | |||
| 123 | 13 | protected static function getApiData($url) |
|
| 128 | |||
| 129 | 29 | protected static function getSemRushDatabase($db) |
|
| 135 | |||
| 136 | 36 | protected static function guardDomainIsValid($domain) |
|
| 142 | |||
| 143 | 29 | protected static function guardDatabaseIsValid($database) |
|
| 149 | |||
| 150 | 8 | protected static function guardValidArgsForGetDomainGraph($reportType, $width, $height, $lang) |
|
| 168 | |||
| 169 | 12 | protected static function getBackendData($url, $db, $reportType) |
|
| 184 | |||
| 185 | 15 | View Code Duplication | protected static function getBackendUrl($url, $db, $reportType) |
| 193 | |||
| 194 | 11 | View Code Duplication | protected static function getWidgetUrl($url, $db, $reportType) |
| 202 | |||
| 203 | 8 | protected static function getWidgetData($url, $db, $reportType, $valueKey) |
|
| 211 | |||
| 212 | 29 | protected static function checkDatabase($db) |
|
| 216 | |||
| 217 | /** |
||
| 218 | * |
||
| 219 | * @throws E |
||
| 220 | */ |
||
| 221 | 20 | View Code Duplication | protected static function exc($err) |
| 222 | { |
||
| 223 | 20 | $e = ($err == 'db') ? "Invalid database. Choose one of: " . |
|
| 224 | 20 | substr( implode(", ", self::getDBs()), 0, -2) : $err; |
|
| 225 | 20 | throw new E($e); |
|
| 226 | exit(0); |
||
| 227 | } |
||
| 228 | |||
| 229 | 36 | protected static function getDomainFromUrl($url) |
|
| 230 | { |
||
| 231 | 36 | $url = parent::getUrl($url); |
|
| 232 | 36 | $domain = Helper\Url::parseHost($url); |
|
| 233 | 36 | static::guardDomainIsValid($domain); |
|
| 234 | |||
| 235 | 29 | return $domain; |
|
| 236 | } |
||
| 237 | |||
| 238 | 29 | protected static function getValidDatabase($db) |
|
| 246 | } |
||
| 247 |
This check looks for a call to a parent method whose name is different than the method from which it is called.
Consider the following code:
The
getFirstName()method in theSoncalls the wrong method in the parent class.