重构案例1 — ECShop (lib_common.php build_url 函数)
重构案例之 ECShop_V2.7.3_UTF8_release0411/upload/includes/lib_common.php 第1490行的 build_uri 函数。
重构之前的 build_url 函数有大概 400 行左右的代码,而且 switch 的条件分支里还夹杂了 if 的条件。故将 build_uri 函数试着重构成了 UriRewrite 类。
代码1 重构前的 build_url 函数代码
/** * 重写 URL 地址 * * @access public * @param string $app 执行程序 * @param array $params 参数数组 * @param string $append 附加字串 * @param integer $page 页数 * @param string $keywords 搜索关键词字符串 * @return void */ function build_uri($app, $params, $append = '', $page = 0, $keywords = '', $size = 0) { static $rewrite = NULL; if ($rewrite === NULL) { $rewrite = intval($GLOBALS['_CFG']['rewrite']); } $args = array('cid' => 0, 'gid' => 0, 'bid' => 0, 'acid' => 0, 'aid' => 0, 'sid' => 0, 'gbid' => 0, 'auid' => 0, 'sort' => '', 'order' => '', ); extract(array_merge($args, $params)); $uri = ''; switch ($app) { case 'category': if (empty($cid)) { return false; } else { if ($rewrite) { $uri = 'category-' . $cid; if (isset($bid)) { $uri .= '-b' . $bid; } if (isset($price_min)) { $uri .= '-min'.$price_min; } if (isset($price_max)) { $uri .= '-max'.$price_max; } if (isset($filter_attr)) { $uri .= '-attr' . $filter_attr; } if (!empty($page)) { $uri .= '-' . $page; } if (!empty($sort)) { $uri .= '-' . $sort; } if (!empty($order)) { $uri .= '-' . $order; } } else { $uri = 'category.php?id=' . $cid; if (!empty($bid)) { $uri .= '&brand=' . $bid; } if (isset($price_min)) { $uri .= '&price_min=' . $price_min; } if (isset($price_max)) { $uri .= '&price_max=' . $price_max; } if (!empty($filter_attr)) { $uri .='&filter_attr=' . $filter_attr; } if (!empty($page)) { $uri .= '&page=' . $page; } if (!empty($sort)) { $uri .= '&sort=' . $sort; } if (!empty($order)) { $uri .= '&order=' . $order; } } } break; case 'goods': if (empty($gid)) { return false; } else { $uri = $rewrite ? 'goods-' . $gid : 'goods.php?id=' . $gid; } break; case 'brand': if (empty($bid)) { return false; } else { if ($rewrite) { $uri = 'brand-' . $bid; if (isset($cid)) { $uri .= '-c' . $cid; } if (!empty($page)) { $uri .= '-' . $page; } if (!empty($sort)) { $uri .= '-' . $sort; } if (!empty($order)) { $uri .= '-' . $order; } } else { $uri = 'brand.php?id=' . $bid; if (!empty($cid)) { $uri .= '&cat=' . $cid; } if (!empty($page)) { $uri .= '&page=' . $page; } if (!empty($sort)) { $uri .= '&sort=' . $sort; } if (!empty($order)) { $uri .= '&order=' . $order; } } } break; case 'article_cat': if (empty($acid)) { return false; } else { if ($rewrite) { $uri = 'article_cat-' . $acid; if (!empty($page)) { $uri .= '-' . $page; } if (!empty($sort)) { $uri .= '-' . $sort; } if (!empty($order)) { $uri .= '-' . $order; } if (!empty($keywords)) { $uri .= '-' . $keywords; } } else { $uri = 'article_cat.php?id=' . $acid; if (!empty($page)) { $uri .= '&page=' . $page; } if (!empty($sort)) { $uri .= '&sort=' . $sort; } if (!empty($order)) { $uri .= '&order=' . $order; } if (!empty($keywords)) { $uri .= '&keywords=' . $keywords; } } } break; case 'article': if (empty($aid)) { return false; } else { $uri = $rewrite ? 'article-' . $aid : 'article.php?id=' . $aid; } break; case 'group_buy': if (empty($gbid)) { return false; } else { $uri = $rewrite ? 'group_buy-' . $gbid : 'group_buy.php?act=view&id=' . $gbid; } break; case 'auction': if (empty($auid)) { return false; } else { $uri = $rewrite ? 'auction-' . $auid : 'auction.php?act=view&id=' . $auid; } break; case 'snatch': if (empty($sid)) { return false; } else { $uri = $rewrite ? 'snatch-' . $sid : 'snatch.php?id=' . $sid; } break; case 'search': break; case 'exchange': if ($rewrite) { $uri = 'exchange-' . $cid; if (isset($price_min)) { $uri .= '-min'.$price_min; } if (isset($price_max)) { $uri .= '-max'.$price_max; } if (!empty($page)) { $uri .= '-' . $page; } if (!empty($sort)) { $uri .= '-' . $sort; } if (!empty($order)) { $uri .= '-' . $order; } } else { $uri = 'exchange.php?cat_id=' . $cid; if (isset($price_min)) { $uri .= '&integral_min=' . $price_min; } if (isset($price_max)) { $uri .= '&integral_max=' . $price_max; } if (!empty($page)) { $uri .= '&page=' . $page; } if (!empty($sort)) { $uri .= '&sort=' . $sort; } if (!empty($order)) { $uri .= '&order=' . $order; } } break; case 'exchange_goods': if (empty($gid)) { return false; } else { $uri = $rewrite ? 'exchange-id' . $gid : 'exchange.php?id=' . $gid . '&act=view'; } break; default: return false; break; } if ($rewrite) { if ($rewrite == 2 && !empty($append)) { $uri .= '-' . urlencode(preg_replace('/[\.|\/|\?|&|\+|\\\|\'|"|,]+/', '', $append)); } $uri .= '.html'; } if (($rewrite == 2) && (strpos(strtolower(EC_CHARSET), 'utf') !== 0)) { $uri = urlencode($uri); } return $uri; }
代码2 重构后的 UriRewrite 类,由于时间关系,类中没有写完所有的代码
<?php /* * URL重写类 * */ class UriRewrite { private $m_app; private $m_params; private $m_append; private $m_page; private $m_keywords; private $m_size; private $m_rewrite; private $m_methodTable = array( 'category'=>'CreateByCategory', 'goods'=>'CreateByGoods', 'brand'=>'CreateByBrand', 'article_cat'=>'CreateByArticleCat', 'article'=>'CreateByArticle', 'group_buy'=>'CreateByGroupBuy', 'auction'=>'CreateByAuction', 'snatch'=>'CreateBySnatch', 'search'=>'CreateBySearch', 'exchange'=>'CreateByExchange', 'exchange_goods'=>'CreateByExchangeGoods' ); private $m_result; public function __construct($app, $params, $append = '', $page = 0, $keywords = '', $size = 0) { $this->m_app = $app; $this->m_params = $params; $this->m_append = $append; $this->m_page = $page; $this->m_keywords = $keywords; $this->m_size = $size; $this->m_rewrite = intval($GLOBALS['_CFG']['rewrite']); } public function Create() { $args = array( 'cid' => 0, 'gid' => 0, 'bid' => 0, 'acid' => 0, 'aid' => 0, 'sid' => 0, 'gbid' => 0, 'auid' => 0, 'sort' => '', 'order' => '' ); array_merge($args, $this->m_params); if(!array_key_exists($this->m_app, $this->m_methodTable)) { return false; } $uri = $this->{$this->m_methodTable[$this->m_app]}(); $uri = $this->DoByAppend($uri); $uri = $this->DoByCharset($uri); return $uri; } protected function CreateByCategory() { if (empty($this->m_params['cid'])) { return false; } $this->m_rewrite = 'category-'.$this->m_params['cid']; return $this->AddBID()->AddPriceMin()->AddPriceMax()->AddFilterAttr()->AddPage()->AddSort()->AddOrder()->Result(); } protected function CreateByGoods() {} protected function CreateByBrand() {} protected function CreateByArticleCat() {} protected function CreateByArticle() {} protected function CreateByGroupBuy() {} protected function CreateByAuction() {} protected function CreateBySnatch() {} protected function CreateBySearch() {} protected function CreateByExchange() {} protected function CreateByExchangeGoods() {} private function Result() { return empty($this->m_result)? false : $this->m_result; } private function DoByAppend($uri) { if ($this->m_rewrite) { if ($this->m_rewrite == 2 && !empty($this->m_append)) { $uri .= '-' . urlencode(preg_replace('/[\.|\/|\?|&|\+|\\\|\'|"|,]+/', '', $this->m_append)); } $uri .= '.html'; } return $uri; } private function DoByCharset($uri) { if (($this->m_rewrite == 2) && (strpos(strtolower(EC_CHARSET), 'utf') !== 0)) { $uri = urlencode($uri); } return $uri; } private function AddCID($uri) { if($this->m_rewrite) { $this->m_rewrite = ''; } else { $this->m_rewrite = ''; } return $this; } private function AddGID($uri) {} private function AddBID($uri) {} private function AddACID($uri) {} private function AddAID($uri) {} private function AddSID($uri) {} private function AddGBID($uri) {} private function AddAUID($uri) {} private function AddSort($uri) {} private function AddOrder($uri) {} private function AddPriceMin($uri) {} private function AddPriceMax($uri) {} private function AddFilterAttr($uri) {} private function AddPage($uri) {} } ?>
在这次重构中,使用到了一个 方法表 的概念。就是将原本 switch 的条件选择,通过 方法表 定位到对类方法的动态调用。
// 方法表的定义 private $m_methodTable = array( 'category'=>'CreateByCategory', 'goods'=>'CreateByGoods', 'brand'=>'CreateByBrand', 'article_cat'=>'CreateByArticleCat', 'article'=>'CreateByArticle', 'group_buy'=>'CreateByGroupBuy', 'auction'=>'CreateByAuction', 'snatch'=>'CreateBySnatch', 'search'=>'CreateBySearch', 'exchange'=>'CreateByExchange', 'exchange_goods'=>'CreateByExchangeGoods' ); /* * 方法表的调用。还可以使用 call_user_func * * call_user_func(array($this, $this->m_methodTable[$this->m_app])); */ $this->{$this->m_methodTable[$this->m_app]}();