摘要:業(yè)務(wù)代碼風(fēng)格的幾個建議關(guān)于循環(huán)體內(nèi)重復(fù)調(diào)用的問題代碼示例是一個可能超出個數(shù)據(jù)的大變量以上代碼塊是有非常嚴(yán)重問題的。所以,業(yè)務(wù)代碼應(yīng)盡量避免使用類似代碼。建議每個方法的代碼不超過行,除非情況特殊。
業(yè)務(wù)代碼風(fēng)格的幾個建議
關(guān)于循環(huán)體內(nèi)重復(fù)調(diào)用的問題
代碼示例:
// $array是一個可能超出1000個數(shù)據(jù)的大變量 foreach ($array as $ar) { $model = new Model(); $modelData = $model->findOne(["id" => $ar["id"]]); $modelData["is_less"] = $modelData["tag"] == 3 ? true : false; $model2 = new AnotherModel(); $model2->find(["id" => $ar["id"]])->update(["is_less" => $modelData["is_less"]]); }
以上代碼塊是有非常嚴(yán)重問題的。
在循環(huán)體中,不能重復(fù)使用數(shù)據(jù)庫查詢太多次,尤其是相似或一致的sql,一定要批量查詢獲取數(shù)據(jù)之后再做相應(yīng)邏輯層面的處理。如果循環(huán)次數(shù)較多,不僅僅會體現(xiàn)在循環(huán)邏輯較慢上,而且在并發(fā)讀寫的業(yè)務(wù)中由于頻繁讀取硬盤以及鎖表等可能會給數(shù)據(jù)庫服務(wù)器造成巨大壓力。
所以以上代碼可以改造成:
$ids = array_columns($array, "id"); if ($ids) { $model = new Model(); $modelDataList = $model->where(["in", "id", $ids])->all(); $modelDataList = array_combine(array_columns($modelDataList, "id"), $modelDataList); } foreach ($array as $ar) { $modelData = empty($modelDataList[$ar["id"]]) ? [] : $modelDataList[$ar["id"]]; if (!$modelData) { continue; } $modelData["is_less"] = $modelData["tag"] == 3 ? true : false; $model2 = new AnotherModel(); $model2->find(["id" => $ar["id"]])->update(["is_less" => $modelData["is_less"]]); }
還有一個例子,如:
foreach($ids as $id) { $data = RpcService::getMyData(["my_id" => $id]); $data["field1"] = $data["field2"] + $data["field3"]; $sendPost = RpcService::sendToBoss(["field1" => $data["field1"]]); }
像這種通過接口獲取數(shù)據(jù)或者更新數(shù)據(jù)的,一般不能在循環(huán)體內(nèi)重復(fù)調(diào)用,因?yàn)閔ttp或者其他實(shí)現(xiàn)rpc的網(wǎng)絡(luò)協(xié)議或多或少都會慢在數(shù)據(jù)傳輸上,而且對方業(yè)務(wù)的實(shí)現(xiàn)一般也不建議調(diào)用方循環(huán)調(diào)用,所以如果有批量調(diào)用接口的需求,應(yīng)該要求接口提供方提供批量操作的接口,在循環(huán)體外進(jìn)行操作。
以上代碼可修改為:
$dataList = RpcService::getMyDataList(["ids" => $ids]); array_walk($dataList, function () { // 處理字段 }); RpcService::multiSendToBoss(["list" => array_columns($dataList, "field1")]);
還有文件讀取也是類似,php讀寫文件效率并不高,應(yīng)避免頻繁讀寫相同文件。例如:
$readFilePath = "current_file"; foreach($writeFilePaths as $path) { $content = file_get_content(realpath($readFilePath)); file_put_content($path, $content); }
應(yīng)將文件內(nèi)容放在循環(huán)體外部。
其他但凡是有耗時或不建議頻繁調(diào)用的邏輯,都應(yīng)該寫在循環(huán)體外。
關(guān)于業(yè)務(wù)層面類調(diào)用或方法調(diào)用可讀性的問題。
關(guān)于這一點(diǎn),先看一下代碼示例:
class DemoClass { public $handler = []; public function handlerRegister(Handler $handler) { $this->handler[] = $hanlder; } public function run($id, $params) { foreach ($this->handler as $h) { if ($h->id === $id) { return $h->handle($params); } } } } class Handler { public $id; public function handle($params) { $result = call_user_func($params["callback"], $params["params"]); $resultData = (new $result)->getData(); $next = $params["next"]; return $next($resultData); } }
call_user_func、call_user_func_array、Reflection類等可以對變量里的某些內(nèi)容直接實(shí)例化或者調(diào)用,這在機(jī)器編譯運(yùn)行看來是沒什么問題的,但是人看的話就比較費(fèi)心了,你要追根溯源搞清楚調(diào)用的是啥,反射的是啥,雖然寫起來很簡單粗暴,但對讀的人不太友好。況且,即便是phpstorm這樣的強(qiáng)大的IDE,也不能幫你識別追溯這些變量的源頭。
所以,業(yè)務(wù)代碼應(yīng)盡量避免使用類似代碼。
但是,如果你寫的是底層腳手架,是豐富框架功能的一個工具包,那么你可以按照自己的想法來,使用者看不看得懂就不重要了。所以像以上的例子往往出現(xiàn)在vendor依賴包中的比較多,寫起來比較簡單,也不必?fù)?dān)心別人看不懂的問題。
關(guān)于輔助方法編寫的問題
這一點(diǎn)不同的框架有不同的表現(xiàn),可能有一些框架有自身實(shí)現(xiàn)思想的考慮,不方便全局調(diào)用一些東西,但目前很多框架都使用了容器,所以使用輔助方法進(jìn)一步精簡代碼就有些必要了。
寫有輔助方法文件,需要在框架加載過程中,業(yè)務(wù)使用之前引入,最好是全局引入。
比如Yii2中如果要實(shí)現(xiàn)一個json返回,需要寫以下代碼:
Yii::$app->response->format = Response::FORMAT_JSON; return [ "code" => 1, "message" => "success" ];
如果你寫了一個輔助方法如下:
function ajax(array $data) { Yii::$app->response->format = Response::FORMAT_JSON; return $data; }
那么代碼可以寫成:
return ajax([ "code" => 1, "message" => "success" ]);
又比如:獲取一個post提交的所有參數(shù):
$post = Yii::$app->request->post(); // 獲取所有 $field1 = Yii::$app->request->post("field1"); // 獲取其中的某個參數(shù)
輔助方法如下:
function post($key = null, default = null) { if ($key === null) { return Yii::$app->request->post(); // 獲取所有 } return Yii::$app->request->post($key, $default) }
調(diào)用如下:
$post = post(); $field1 = post("field1");
又比如,根據(jù)鍵銷毀數(shù)組中的某一個值。
// 原生寫法 if (isset($arr[$key])) { unset($key); } // 輔助方法 function array_pull(&$arr, $key) { if (isset($arr[$key])) { unset($key); } } // 調(diào)用 array_pull($arr, $key);
關(guān)于邏輯塊復(fù)用和可讀性的問題
比如:
public function handle($params) { $dataList = (new Model)->query($params)->all(); $return = []; foreach ($dataList as $data) { if ($data["key"] == 1) { $data["field1"] = "123"; } else if ($data["key"] == 2) { $data["field1"] = "678"; $data["field2"] = "7hj"; } else if ($data["key"] == 3) { $data["field1"] = "uyo"; } else { $data["field1"] = "other"; } if ($data["field1"] == "123") { $other = [ "other1" => 34, "other2" => 35, "other3" => 98 ]; $return[] = $other; } elseif ($data["field1"] == "678") { $other = [ "other1" => 341, "other2" => 351, "other3" => 981 ]; if ($data["field2"] == "7hj") { $other = [ "other1" => 3412, "other2" => 3512, "other3" => 9812 ]; } $return[] = $other; } else if ($data["field1"] === "uyo") { $other = [ "other1" => 3412, "other2" => 3512, "other3" => 9812 ]; $return[] = $other; } else { $other = [ "other1" => 34123, "other2" => 35123, "other3" => 98123 ]; $return[] = $other; } } }
以上代碼出現(xiàn)的問題主要有三個:無注釋、判斷條件太多、邏輯塊無法復(fù)用。
如果出現(xiàn)更復(fù)雜的邏輯,這段代碼無疑可能會超過100多行,這在開發(fā)維護(hù)人員看起來是很艱難的。
注釋問題和判斷條件太多可能由于業(yè)務(wù)的問題,有時候無法避免,這里重點(diǎn)說一下邏輯塊復(fù)用。
以上的代碼片段中,dataList的獲取,應(yīng)該是一個獨(dú)立的方法,因?yàn)閷砜赡芷渌δ芤矔褂猛瑯拥姆椒ǐ@取對應(yīng)數(shù)據(jù);針對于data["field1"]的取值,也應(yīng)該是一個獨(dú)立的方法;下面對于data["field1"]的判斷,也應(yīng)該是一個獨(dú)立方法。這就需要對代碼拆分,既能夠保證代碼簡潔性、復(fù)用性和可讀性,也避免多個無用變量在一個邏輯塊中積累。
在代碼邏輯中,一個功能應(yīng)該由一個方法來實(shí)現(xiàn),一個方法也應(yīng)該只做一件事。
這樣把這段代碼拆分之后,將會變?yōu)椋?/p>
public function getDataList($params) { return (new Model)->query($params)->all(); } public function handleField($data) { if ($data["key"] == 1) { $data["field1"] = "123"; } else if ($data["key"] == 2) { $data["field1"] = "678"; $data["field2"] = "7hj"; } else if ($data["key"] == 3) { $data["field1"] = "uyo"; } else { $data["field1"] = "other"; } return $data; } public function getOther() { if ($data["field1"] == "123") { $other = [ "other1" => 34, "other2" => 35, "other3" => 98 ]; } elseif ($data["field1"] == "678") { $other = [ "other1" => 341, "other2" => 351, "other3" => 981 ]; if ($data["field2"] == "7hj") { $other = [ "other1" => 3412, "other2" => 3512, "other3" => 9812 ]; } } else if ($data["field1"] === "uyo") { $other = [ "other1" => 3412, "other2" => 3512, "other3" => 9812 ]; } else { $other = [ "other1" => 34123, "other2" => 35123, "other3" => 98123 ]; } return $other; } public function handle($params) { $dataList = $this->getDataList($params); $return = []; foreach ($dataList as $data) { $data = $this->handleField($data); $return[] = $other; } return $return; }
這幾個方法各自承擔(dān)一個功能,只完成一件事。handle()方法只是用來組織幾個方法的數(shù)據(jù),簡單明了。
建議每個方法的代碼不超過30行,除非情況特殊。
關(guān)于公共方法書寫風(fēng)格的建議
關(guān)于公共方法調(diào)用的代碼風(fēng)格,應(yīng)該遵循調(diào)用者最少知道的原則,調(diào)用者只需按照對應(yīng)參數(shù)傳入即可,后面的邏輯復(fù)雜性,原則上不必被調(diào)用者知道,且調(diào)用者應(yīng)能夠充分知曉正確與錯誤信息,且應(yīng)保證其健壯性。
涉及到傳入?yún)?shù)為數(shù)組的,應(yīng)告知調(diào)用者該數(shù)組內(nèi)部參數(shù)的詳細(xì)說明,或在注釋中給出對應(yīng)示例。
頁面下載使用專用文件服務(wù)器
涉及到web頁面直接生成數(shù)據(jù)下載的,應(yīng)盡量使用專用的文件服務(wù)器,而不是直接在頁面進(jìn)行下載,且下載應(yīng)盡量使用異步生成文件。
例如用戶在點(diǎn)擊頁面下載按鈕之后跳入自己的下載頁面,這個頁面上有自己的文件下載的歷史表格,有狀態(tài)標(biāo)記文件是否可以進(jìn)行下載,當(dāng)后臺將文件生成好上傳到文件服務(wù)器之后,會標(biāo)記成可下載。
好處:記錄下載歷史、歷史文件下載、下載性能優(yōu)化、可以處理大文件。
壞處:需要多做一個頁面和一張表,且需要等待文件生成上傳至文件服務(wù)器的時間。
文件服務(wù)器可以使用對象云。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/31235.html
摘要:面向服務(wù)面向服務(wù)的基礎(chǔ)面向服務(wù)的三層應(yīng)用層,服務(wù)層,數(shù)據(jù)層應(yīng)用層用于給用戶展示,,,,安卓。在服務(wù)器端,進(jìn)程保持睡眠狀態(tài)直到調(diào)用信息到達(dá)為止。編譯完成,提示我們已經(jīng)在下了。 面向服務(wù) 面向服務(wù)的基礎(chǔ) 面向服務(wù)的三層:應(yīng)用層,服務(wù)層,數(shù)據(jù)層 * 應(yīng)用層:用于給用戶展示,PC,H5,IOS,安卓。 * 服務(wù)層:業(yè)務(wù)邏輯,提供接口(商品,訂單,支付,用戶,物流)。 * 數(shù)據(jù)層:提供數(shù)據(jù)支持(...
摘要:作為開發(fā)中應(yīng)用最廣泛的開源腳本語言,憑借庫類豐富,使用簡單,安全等特點(diǎn),成為和等互聯(lián)網(wǎng)巨頭和全球超過網(wǎng)站的主要開發(fā)語言,然而性能問題是一直以來飽受詬病的,來自開發(fā)組的高馳濤同學(xué)將為我們帶來他對性能優(yōu)化方面的思考和建議。 PHP作為Web開發(fā)中應(yīng)用最廣泛的開源腳本語言,憑借庫類豐富,使用簡單,安全等特點(diǎn),成為Facebook和BAT等互聯(lián)網(wǎng)巨頭和全球超過70%網(wǎng)站的主要開發(fā)語言,然而性能...
摘要:讓達(dá)到最高性能的幾個建議懶得排版了,伯樂在線鏈接原文出處惠新宸歡迎分享原創(chuàng)到伯樂頭條已經(jīng)發(fā)布了,作為十年來最大的版本升級,最大的性能升級,在多放的測試中都表現(xiàn)出很明顯的性能提升,然而,為了讓它能發(fā)揮出最大的性能,我還是有幾件事想提醒下。 讓 PHP7 達(dá)到最高性能的幾個建議 懶得排版了,伯樂在線鏈接:http://blog.jobbole.com/95657/ 原文出處: 惠新宸(@L...
摘要:如需要支持熱啟動,請自行谷歌,大概原理就是用監(jiān)控文件變更,如果更新了重啟如果正式環(huán)境中還可以自己寫個部署腳本,后重啟服務(wù)等,方法很多不一一列舉。 1 Laravel的速度瓶頸在哪? 1.1 已有的一些優(yōu)化方法 1.1.1 laravel官方提供了一些優(yōu)化laravel的優(yōu)化方法 php artisan optimize php artisan config:cache php arti...
閱讀 1207·2021-11-17 09:33
閱讀 3613·2021-09-28 09:42
閱讀 3343·2021-09-13 10:35
閱讀 2498·2021-09-06 15:00
閱讀 2445·2021-08-27 13:12
閱讀 3614·2021-07-26 23:38
閱讀 1849·2019-08-30 15:55
閱讀 542·2019-08-30 15:53