ホームページ >バックエンド開発 >PHPチュートリアル >PHP の再構築と最適化の例 - テンプレート メソッドの適用 pattern_PHP チュートリアル
最近、php プロジェクトを最適化し、自分の経験を記録し、直接作業を開始しました。 。 。
中 PHP は、企業のプロジェクトで主にページ表示に使用され、バックエンドからバックエンドへのデータ要求の形式は JSON です。最適化の前にサービスコードを見てみましょう:[php]
require_once('../../../global.php');
require_once(INCLUDE_PATH . '/discache/CacherManager.php');
require_once(INCLUDE_PATH.'/oracle_oci.php');
require_once(INCLUDE_PATH.'/caihui/cwsd.php');
header('コンテンツタイプ: text/plain; charset=utf-8');
$max_age = isset($_GET['max-age']) ? $_GET['最大年齢']*1 : 15*60;
if($max_age < 30) {
$max_age = 30;
}
header('キャッシュ制御: max-age='.$max_age);
// 通过将url进行ハッシュ作缓冲key
$url = $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$url_hash = md5($url);
//エコー "/finance/hs/marketdata/segment/${url_hash}.json";
if (!CacherManager::cachePageStart(CACHER_MONGO, "/finance/hs/marketdata/segment/${url_hash}.json", 60*60)) {
// 查询条件
$page = isset($_GET['page']) ? $_GET['ページ']*1 : 0;
$count = isset($_GET['count']) ? $_GET['カウント']*1 : 30;
$type = isset($_GET['type']) ? $_GET['タイプ'] : 'クエリ';
$sort = isset($_GET['sort']) ? $_GET['ソート'] : 'シンボル';
$order = isset($_GET['order']) ? $_GET['順序'] : '説明';
$callback = isset($_GET['callback']) ? $_GET['コールバック'] : null;
$fieldsstring = isset($_GET['fields']) ? $_GET['フィールド'] : null;
$querystring = isset($_GET['query']) ? $_GET['クエリ'] : null;
$symbol=isset($_GET['symbol'])?$_GET['symbol']:'';
$date=isset($_GET['日付'])?$_GET['日付']:'';
if ($type == 'クエリ') {
$queryObj = preg_split('/:|;/', $querystring, -1);
for($i=0; $i
if($queryObj[$i]=='シンボル'){
$symbol = $queryObj[$i+1];
}
if($queryObj[$i]=='日付'){
$date = $queryObj[$i+1];
}
}
}
// 查询列表
$oci = ntes_get_caihui_oci();
$stocklist = 配列();
$cwsd = 新しい名前空間daocaihuiCwsd($oci);
$stockcurror = $cwsd->getCznlList($symbol,$date,$sort,$order,$count*($page),$count);
$sumrecords=$cwsd->getRecordCount($symbol,$date);
$i=0;
//var_dump($symbol,$date,$sort,$order,$count*($page),$count);
foreach($stockcurror as $item){
$item['RSMFRATIO1422']=isset($item['RSMFRATIO1422'])?number_format($item['RSMFRATIO1422'],2).'%':'--';
$item['RSMFRATIO1822']=isset($item['RSMFRATIO1822'])?number_format($item['RSMFRATIO1822'],2).'%':'--';
$item['RSMFRATIO22']=isset($item['RSMFRATIO22'])?number_format($item['RSMFRATIO22'],2).'%':'--';
$item['RSMFRATIO10']=isset($item['RSMFRATIO10'])?number_format($item['RSMFRATIO10'],2):'--';
$item['RSMFRATIO12']=isset($item['RSMFRATIO12'])?number_format($item['RSMFRATIO12'],2):'--';
$item['RSMFRATIO4']=isset($item['RSMFRATIO4'])?number_format($item['RSMFRATIO4'],2):'--';
$item['RSMFRATIO18']=isset($item['RSMFRATIO18'])?number_format($item['RSMFRATIO18'],2):'--';
$item['RSMFRATIO14']=isset($item['RSMFRATIO14'])?number_format($item['RSMFRATIO14'],2):'--';
$item['CODE']=$item['EXCHANGE'].$item['SYMBOL'];
//$item['REPORTDATE']=isset($item['REPORTDATE'])?$item['REPORTDATE']:'--';
$在庫リスト[$i] = $アイテム
$i=$i+1;
}
// 結果を出力します
$結果 = 配列();
//ページ番号、ページごとのカウント、結果の総数、ページ数、結果リスト
$result['ページ'] = $ページ;
$result['count'] = $count;
$result['order'] = $order
$result['total'] = $i;//$stockcurror->count();
$result['pagecount'] = ceil($sumrecords['SUMRECORD']/$count);
$result['time'] = date('Y-m-d H:i:s');
$result['リスト'] = $ストックリスト
if(emptyempty($callback)){
エコー json_encode($result);
}その他{
echo $callback.'('.json_encode($result).');';
}
CacherManager::cachePageEnd();
}
?>
このサービスによって実現される具体的な機能を見てみましょう:
1. 6 ~ 16 行目、キャッシュパラメータを準備し、キャッシュを有効にします。
2. 19 ~ 41 行目、リクエストパラメータを抽出します。
3. 44 ~ 49 行目、データベースに接続してクエリを実行します。
4. 50~67行目では、データベースクエリの結果を配列に入れます。
5. 71~84行目、jsonデータを準備します。
6. 86 ~ 87 行目、キャッシュをオフにします。
このファイルだけを見ると、問題は次のとおりです:
1. 19~86行目、インデントなし。
2. 44 行目、データベースはリクエストごとに再接続されます。
3. 53 ~ 61 行目では、繰り返されるロジックを関数として抽出し、反復を通じて完成させることができます。
ほとんどのバックエンド サービスがこの構造を採用している場合、問題は、すべてのサービスがキャッシュのオープン、パラメーターの取得、データの取得、JSON 変換、キャッシュのクローズという一連のプロセスを実行する必要があることです。すべての処理において、データを取得するロジックを除いて、他の処理は同じです。コードには繰り返しロジックが多く含まれており、ユーザーに「コピー&ペースト」のような感覚さえ与え、DRY 原則 (Don'trepeat Yourself) に大きく違反しています。したがって、オブジェクト指向の考え方を使用して再構築する必要があります。再構築の過程で、私は常に 1 つの原則を念頭に置いていました。それは、カプセル化変更の原則です。いわゆる変更のカプセル化とは、システム内の定数と変数を区別し、変更に簡単に対処できるように変数をカプセル化することです。
上記の分析により、データを取得するロジックのみが変更され、他のロジックは変更されません。したがって、データを取得するロジックをカプセル化する必要があります。具体的なカプセル化方法は継承または結合です。継承方式を採用し、まずサービスの処理プロセスを次のように抽象化します。
サービス(){
StartCache();
getParam();
getData() // サブクラスによって実装される抽象メソッド
;
toJson();
クローズキャッシュ ()
}
サブクラスが継承するServiceBaseクラスは、データを取得する対応するロジックを実装しています。
[php]
抽象クラス ServiceBase {
パブリック関数 __construct($cache_path, $cache_type, $max_age, $age_explore) {
// リクエストパラメータを取得します
$this->page = $this->getQueryParamDefault('page', 0, INT);
// パラメータを取得する他のロジックを省略します
…
// 応答を生成します
$this->response();
}
/**
*
* サブクラス実装、配列形式でデータを返します
*/
抽象保護関数 data();
/**
*
* サブクラスの実装、すべてのデータの合計数を返します
*/
抽象保護関数 total();
プライベート関数cache() {
$url = $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']
$url_hash = md5($url);
$key = $this->cache_path.$url_hash.'.json';
If(!CacherManager::cachePageStart($this->cache_type, $key, $this->age_cache)){
$this->no_cache();
CacherManager::cachePageEnd();
}
}
プライベート関数 no_cache(){
$data = $this->data();
$total = $this->total();
$this->send_data($data, $total);}
プライベート関数 send_data($data, $total){
// json を変換し、特定のコードを省略します
}
プライベート関数 response() {
header('コンテンツタイプ: text/plain; charset=utf-8');
header('キャッシュ制御: max-age='.$this->age_explore);
If($this->cache_type == NONE || self::$enable_cache == false){
$this->no_cache();
}その他{
$this->cache();
}
}
}
各サービスの抽象親クラスには data と total の 2 つの抽象メソッドがあり、ページングにより Data が追加されます。特定のサービスは ServiceBase を継承し、data メソッドと total メソッドを実装するだけでよく、その他のロジックは親クラスから再利用されます。実際、最適化された ServiceBase では、テンプレート メソッド パターン (Template Method) を使用してアルゴリズムの処理プロセス (サービスの処理プロセス) を定義し、サブクラスで特定の変更の手順 (サービスのデータを取得するロジック) を実装します。特定のサービス)。テンプレート メソッド パターンを使用すると、ステップの変更がクライアントに対して透過的であることが保証され、親クラスのロジックを再利用できます。
H 以下は、上記の PHP が serviceBase を使用した後のコードです:
[php]
クラス CWSDService は ServiceBase を拡張します{
関数 __construct(){
親::__construct();
$oci = ntes_get_caihui_oci();
$this->$cwsd = 新しい名前空間daocaihuiCwsd($oci);
}
パブリック関数 data(){
$stocklist = 配列();
$stockcurror = $this->cwsd->getCznlList($this->query_obj['symbol'],
$this->query_obj['symbol'], $sort, $order, $count*($page), $count);
$filter_list = array('RSMFRATIO1422', 'RSMFRATIO1822', 'RSMFRATIO22',
'RSMFRATIO10'、'RSMFRATIO12'、'RSMFRATIO4'、'RSMFRATIO18'、
'RSMFRATIO14');
$i=0;
foreach($stockcurror as $item){
foreach($filter_list as $k)
$this->filter($item, $k);
$item['CODE']=$item['EXCHANGE'].$item['SYMBOL'];
$stocklist[$i] = $item;
$i=$i+1;
}
$stocklist を返します。
}
パブリック関数 total(){
return $sumrecords=$this->cwsd->getRecordCount($this->query_obj['symbol'],
$this->query_obj['symbol']);
}
プライベート関数フィルター($item, $k){
isset($item[$k])?number_format($item[$k],2).'%':'--';
}
}
new CWSDService('/finance/hs/realtimedata/market/ab', MONGO, 30, 30);
87 行から 32 行に減少したのは、大部分のサブクラスが実行するためであり、特定のサービスは、自分自身の登録を必要とするトラフィック アクセスだけで実現可能です。中間の同じ相互関係は、父クラスの中で使用目的を達成することができますが、同時に、父クラスと子クラスの間の結合性を追加することも承知します。変形すると、具体的な実現はポリシーモードであり、特定のデータを取得することをポリシーとみなし、異なるサービスは異なるポリシーであると考えられるため、時間の関係で説明しない。
厳選した0ne的专栏