最近優化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...