php重構優化一例 模板方法模式應用

2022-09-23 13:48:11 字數 3848 閱讀 6914

最近優化php專案,記錄下經驗,直接上幹活。。。

php在公司專案中主要用於頁面展現,前端有個view,view向後端的service請求資料,資料的傳輸格式是json。下面看優化前的service的**:

[php]

<?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('content-type: text/plain; charset=utf-8'); 

$max_age = isset($_get['max-age']) ? $_get['max-age']*1 : 15*60; 

if($max_age < 30)  

header('cache-control: max-age='.$max_age); 

// 通過將url進行hash作為緩衝key 

// 查詢列表 

$oci = ntes_get_caihui_oci(); 

$stocklist = array(); 

$cwsd = new namespace\dao\caihui\cwsd($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)   

// 輸出結果 

$result = array(); 

// 頁碼page、每頁數量count、結果總數total、分頁數pagecount、結果列表list 

$result['page'] = $page; 

$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['list'] = $stocklist; 

if(emptyempty($callback))else 

cachermanager::cachepageend(); 

} ?> 

下面看一下這個service具體完成的功能:

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行,重複的邏輯,可以提取為乙個函式,然後通過迭代完成。

如果大部分後端service都採用這個結構,那麼問題就是所有的service都需要經過:開啟快取,取參,獲取資料,json轉化,關閉快取這一系列的過程。而在所有過程中,除了獲取資料的邏輯,其他的過程都是一樣的。在**中存在著大量的重複邏輯,甚至給人一種「複製-貼上」的感覺,這嚴重的違背了dry原則(don't repeat yourself)。所以,這裡需要運用物件導向的思想對其重構。而在我重構的過程中,腦海中始終謹記著乙個原則——封裝變化原則。所謂封裝變化,就是區分系統中不變的和可變的,將可變的進行封裝,這樣可以很好過應對變化。

通過上面的分析,只有獲取資料的邏輯是變化的,其他的邏輯是不變的。所以需要對獲取資料的邏輯進行封裝,具體的封裝方式可以採用繼承或組合。我採用的是繼承的方式,首先將service的處理過程抽象為:

service()

抽象出servicebase類,由子類繼承,實現相應的獲取資料的邏輯,子類不需要處理其他的取參、快取等邏輯,這些都被servicebase類處理了。

[php]

abstract class servicebase  

/*** 

* 子類實現,返回陣列格式的資料

*/ abstract protected function data(); 

/*** 

* 子類實現,返回所有資料的總數

*/ abstract protected function total(); 

private function cache()  

} private function no_cache() 

private function send_data($data, $total) 

private function response() else 

} }         這就是各個service的抽象父類,有兩個抽象方法data和total,data是返回陣列格式的資料,tatol是由於分頁加入的。具體的service只要繼承servicebase並實現data和total方法即可,其他的邏輯都是復用的父類的。實際上,優化後的servicebase是使用了模板方法模式(template method),父類定義演算法處理的流程(service的處理過程),子類實現某個具體變化的步驟(具體service的獲取資料的邏輯)。通過使用模板方法模式可以保證步驟的變化對於客戶端是透明的,並且可以復用父類中的邏輯。

下面是上述php採用servicebase後的**:

[php]

class cwsdservice extends servicebase 

public function data() 

return $stocklist; 

} public function total() 

private function filter($item, $k) 

} new cwsdservice('/finance/hs/realtimedata/market/ab', mongo, 30, 30); 

**量從87減少到32行,是因為大部分的邏輯都由父類完成,具體service只需要關注自己的業務邏輯就可以了。通過上面**可以看出繼承可以實現**復用,多個子類中的相同的邏輯可以提取到父類中達到復用的目的;同時,繼承也增加了父類和子類之間的耦合性,這也就是組合由於繼承的方面,如果這個例子採用組合來封裝變化,則具體的實現就是策略模式,將具體獲取資料的邏輯看成是策略,不同的service就是不同的策略,由於時間原因,不再贅述。。。

摘自 chosen0ne的專欄

PHP優化技巧一例

測試資料 有乙個陣列 一共3萬條資料,1mb大小,我分成2種方法放資料來測試 in 1.array.php 直接新建個空 url file php url 檔案,把陣列放進去 2.array.txt 把陣列serialize後儲存 測試程式 複製內容到剪貼簿 for i 0 i 100 i 結果 r...

演算法優化一例

本文將以排序演算法中的插入排序為例,介紹優化演算法,編制高效程式的方法。人們通常用於排序手中橋牌的方法是一次考慮一張牌,將它插入到已經排序過的牌的適當位置中 時刻讓它們保持有序 在計算機實現中,我們需要將較大的元素移到右邊,為插入的元素準備空間,然後再在空位置上插入該元素。該演算法的通常的乙個實現如...

sql優化一例

原sql,查詢總數300,每頁15資料也要8秒 select a from table where date format my time,y m d 2012 08 15 limit 0,15 優化後的sql,查詢總數18000,每頁15的資料只要1秒 select a from table wh...