摘要:前言轉(zhuǎn)眼間成為一名已經(jīng)快整整兩年了,在這期間也對(duì)如何寫(xiě)出可讀性高,便于擴(kuò)展的代碼有了一些自己的想法。所以,我們?cè)趯?xiě)上游代碼時(shí)異常直接拋出即可。通常這樣可以很大程度的提高效率和代碼復(fù)用。
前言
轉(zhuǎn)眼間成為一名PHPer已經(jīng)快整整兩年了,在這期間也對(duì)如何寫(xiě)出可讀性高,便于擴(kuò)展的代碼有了一些自己的想法。
使用引用場(chǎng)景一:遍歷一個(gè)數(shù)組獲取新的數(shù)據(jù)結(jié)構(gòu)
也許你會(huì)這樣寫(xiě):
// 申明一個(gè)新的數(shù)組,組裝成你想要的數(shù)據(jù) $tmp = []; foreach ($arr as $k => $v) { // 取出你想要的數(shù)據(jù) $tmp[$k]["youwant"] = $v["youwant"]; ... // 一系列判斷得到你想要的數(shù)據(jù) if (...) { $tmp[$k]["youwantbyjudge"] = "TIGERB"; } ... } // 最后得要你想要的數(shù)組$tmp ------------------------------------------------------- // 也許你覺(jué)著上面的寫(xiě)法不是很好,那我們下面換種寫(xiě)法 foreach ($arr as $k => $v) { // 一系列判斷得到你想要的數(shù)據(jù) if (...) { // 復(fù)寫(xiě)值為你想要的 $arr[$k]["youwantbyjudge"] = "TIGERB" } ... // 干掉你不想要的結(jié)構(gòu) unset($arr[$k]["youwantdel"]); } // 最后我們得到我們的目標(biāo)數(shù)組$arr
接下來(lái)我們使用引用值:
foreach ($arr as &$v) { // 一系列判斷得到你想要的數(shù)據(jù) if (...) { // 復(fù)寫(xiě)值為你想要的 $v["youwantbyjudge"] = "TIGERB" } ... // 干掉你不想要的結(jié)構(gòu) unset($v["youwantdel"]); } unset($v); // 最后我們得到我們的目標(biāo)數(shù)組$arr
使用引用是不是使我們的代碼更加的簡(jiǎn)潔,除此之外相對(duì)于第一種寫(xiě)法,我們節(jié)省了內(nèi)存空間,尤其是再操作一個(gè)大數(shù)組時(shí)效果是及其明顯的。
場(chǎng)景二:傳遞一個(gè)值到一個(gè)函數(shù)中獲取新的值
基本和數(shù)組遍歷一致,我們只需要聲明這個(gè)函數(shù)的這個(gè)參數(shù)為引用即可,如下:
function decorate(&$arr = []) { # code... } $arr = [ .... ]; // 調(diào)用函數(shù) decorate($arr); // 如上即得到新的值$arr,好處還是節(jié)省內(nèi)存空間使用try...catch...
假如有下面一段邏輯:
class UserModel { public function login($username = "", $password = "") { code... if (...) { // 用戶不存在 return -1; } code... if (...) { // 密碼錯(cuò)誤 return -2; } code... } } class UserController { public function login($username = "", $password = "") { $model = new UserModel(); $res = $model->login($username, $password); if ($res === -1) { return [ "code" => "404", "message" => "用戶不存在" ]; } if ($res === -2) { return [ "code" => "400", "message" => "密碼錯(cuò)誤" ]; } code... } }
我們用try...catch...改寫(xiě)后:
class UserModel { public function login($username = "", $password = "") { code... if (...) { // 用戶不存在 throw new Exception("用戶不存在", "404"); } code... if (...) { // 密碼錯(cuò)誤 throw new Exception("密碼錯(cuò)誤", "400"); } code... } } class UserController { public function login($username = "", $password = "") { try { $model = new UserModel(); $res = $model->login($username, $password); // 如果需要的話,我們可以在這里統(tǒng)一commit數(shù)據(jù)庫(kù)事務(wù) // $db->commit(); } catch (Exception $e) { // 如果需要的話,我們可以在這里統(tǒng)一rollback數(shù)據(jù)庫(kù)事務(wù) // $db->rollback(); return [ "code" => $e->getCode(), "message" => $e->getMessage() ] } } }
通過(guò)使用try...catch...使我們的代碼邏輯更加清晰,try...里只需要關(guān)注業(yè)務(wù)正常的情況,異常的處理統(tǒng)一在catch中。所以,我們?cè)趯?xiě)上游代碼時(shí)異常直接拋出即可。
使用匿名函數(shù)構(gòu)建函數(shù)或方法內(nèi)部的代碼塊
假如我們有一段邏輯,在一個(gè)函數(shù)或者方法里我們需要格式化數(shù)據(jù),但是這個(gè)格式化數(shù)據(jù)的代碼片段出現(xiàn)了多次,如果我們直接寫(xiě)可能會(huì)想下面這樣:
function doSomething(...) { ... // 格式化代碼段 ... ... // 格式化代碼段[重復(fù)的代碼] ... }
我相信大多數(shù)的人應(yīng)該不會(huì)像上面這么寫(xiě),可能都會(huì)像下面這樣:
function doSomething(...) { ... format(...); ... format(...); ... } // 再聲明一個(gè)格式花代碼的函數(shù)或方法 function format() { // 格式化代碼段 ... }
上面這樣的寫(xiě)法沒(méi)有任何的問(wèn)題,最小單元化我們的代碼片段,但是如果這個(gè)format函數(shù)或者方法只是doSomething使用呢?我通常會(huì)像下面這么寫(xiě),為什么?因?yàn)槲艺J(rèn)為在這種上下文的環(huán)境中format和doSomething的一個(gè)子集。
function doSomething() { ... $package = function (...) use (...) { // 同樣use后面的參數(shù)也可以傳引用 // 格式化代碼段 ... }; ... package(...); ... package(...); ... }
實(shí)現(xiàn)類的【懶加載】和實(shí)現(xiàn)設(shè)計(jì)模式的【最少知道原則】
假如有下面這段代碼:
class One { private $instance; // 類One內(nèi)部依賴了類Two // 不符合設(shè)計(jì)模式的最少知道原則 public function __construct() { $this->intance = new Two(); } public function doSomething() { if (...) { // 如果某種情況調(diào)用類Two的實(shí)例方法 $this->instance->do(...); } ... } } ... $instance = new One(); $instance->doSomething(); ...
上面的寫(xiě)法有什么問(wèn)題?
不符合設(shè)計(jì)模式的最少知道原則,類One內(nèi)部直接依賴了類Two
類Two的實(shí)例不是所有的上下文都會(huì)用到,所以浪費(fèi)了資源,有人說(shuō)搞個(gè)單例,但是解決不了實(shí)例化了不用的尷尬
所以我們使用匿名函數(shù)解決上面的問(wèn)題,下面我們這么改寫(xiě):
class One { private $closure; public function __construct(Closure $closure) { $this->closure = $closure; } public function doSomething() { if (...) { // 用的時(shí)候再實(shí)例化 // 實(shí)現(xiàn)懶加載 $instance = $this->closure(); $instance->do(...) } ... } } ... $instance = new One(function () { // 類One外部依賴了類Two return new Two(); }); $instance->doSomething(); ...減少對(duì)if...else...的使用
如果你碰見(jiàn)下面這種類型的代碼,那一定是個(gè)黑洞。
function doSomething() { if (...) { if (...) { ... } esle { ... } } else { if (...) { ... } esle { ... } } }
提前return異常
細(xì)心的你可能會(huì)發(fā)現(xiàn)上面這種情況,可能絕大多數(shù)else代碼里都是在處理異常情況,更有可能這個(gè)異常代碼特別簡(jiǎn)單,通常我會(huì)這么去做:
// 如果是在一個(gè)函數(shù)里面我會(huì)先處理異常的情況,然后提前return代碼,最后再執(zhí)行正常的邏輯 function doSomething() { if (...) { // 異常情況 return ...; } if (...) { // 異常情況 return ...; } // 正常邏輯 ... } // 同樣,如果是在一個(gè)類里面我會(huì)先處理異常的情況,然后先拋出異常 class One { public function doSomething() { if (...) { // 異常情況 throw new Exception(...); } if (...) { // 異常情況 throw new Exception(...); } // 正常邏輯 ... } }
關(guān)聯(lián)數(shù)組做map
如果我們?cè)诳蛻舳俗鰶Q策,通常我們會(huì)判斷不同的上下文在選擇不同策略,通常會(huì)像下面一樣使用if或者switch判斷:
class One { public function doSomething() { if (...) { $instance = new A(); } elseif (...) { $instance = new A(); } else { $instance = new C(); } $instance->doSomething(...); ... } }
上面的寫(xiě)法通常會(huì)出現(xiàn)大量的if語(yǔ)句或者switch語(yǔ)句,通常我會(huì)使用一個(gè)map來(lái)映射不同的策略,像下面這樣:
class One { private $map = [ "a" => "namespaceA", // 帶上命名空間,因?yàn)樽兞渴莿?dòng)態(tài)的 "b" => "namespaceB", "c" => "namespaceC" ]; public function doSomething() { ... $instance = new $this->map[$strategy];// $strategy是"a"或"b"或"c" $instance->doSomething(...); ... } }使用接口
為什么要使用接口?極大的便于后期的擴(kuò)展和代碼的可讀性,例如設(shè)計(jì)一個(gè)優(yōu)惠系統(tǒng),不同的商品只是在不同的優(yōu)惠策略下具備不同的優(yōu)惠行為,我們定義一個(gè)優(yōu)惠行為的接口,最后對(duì)這個(gè)接口編程即可,偽代碼如下
Interface Promotion { public function promote(...); } class OnePromotion implement Promotion { public function doSomething(...) { ... } } class TwoPromotion implement Promotion { public function doSomething(...) { ... } }控制器拒絕直接的DB操作
最后我想說(shuō)的是永遠(yuǎn)拒絕在你的Controller里直接操作DB,為什么?我們的程序絕大多數(shù)的操作基本都是增刪改查,可能是查詢的where條件和字段不同,所以有時(shí)候我們可以抽象的把對(duì)數(shù)據(jù)庫(kù)增刪改查的方法寫(xiě)到model中,通過(guò)參數(shù)暴露我們的where,fields條件。通常這樣可以很大程度的提高效率和代碼復(fù)用。比如像下面這樣:
class DemoModel implement Model { public function getMultiDate($where = [], $fields = ["id"], $orderby = "id asc") { $this->where($where) ->field($fields) ->orderby($orderby) ->get(); } }最后
如果有寫(xiě)的不對(duì)的地方,歡迎大家指正,THX~
Easy PHP:一個(gè)極速輕量級(jí)的PHP全??蚣?/pre>掃面下方二維碼關(guān)注我的技術(shù)公眾號(hào),及時(shí)為大家推送我的原創(chuàng)技術(shù)分享
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/30605.html
摘要:大會(huì)年,我去了。小會(huì)值得一提的是,今年月份,我參加了一個(gè)的分享會(huì)。出游沙巴這是部門(mén)組織的出游,獲得了最佳團(tuán)隊(duì),拿到了一筆經(jīng)費(fèi),于是有了這次出游。于是,我的下個(gè)目的地是西藏。 轉(zhuǎn)眼間 2017 年過(guò)去了。我已經(jīng)不能說(shuō)自己是去年的畢業(yè)生了,時(shí)光匆匆,感覺(jué)自己越來(lái)越老了。 這一年,我所經(jīng)歷的,讓我收獲很多,讓我懂得很多,讓我明白了很多。也許是明確了某一個(gè)目標(biāo),也許是其它的什么,我覺(jué)得,201...
摘要:大家好,推薦下我們團(tuán)隊(duì)自己研發(fā)的框架為現(xiàn)代化的準(zhǔn)備的。可拔插,擴(kuò)展性強(qiáng)。借鑒了等優(yōu)秀框架。有興趣的可以關(guān)注下。最渴望有人給我們提交。中文文檔基礎(chǔ)已經(jīng)寫(xiě)完,剩下努力寫(xiě)中。。。 大家好,推薦下我們團(tuán)隊(duì)自己研發(fā)的框架:tastphp 為現(xiàn)代化的phper準(zhǔn)備的??砂尾澹瑪U(kuò)展性強(qiáng)。借鑒了Symfony、Laravel、Silex等優(yōu)秀框架。 有興趣的可以關(guān)注下 tastphp。最渴望有人給...
摘要:語(yǔ)言行為及特征狀態(tài)看不懂任何英語(yǔ)技術(shù),英語(yǔ)文檔,凡事沒(méi)有培訓(xùn)部在搞的,只有英文文檔的東西國(guó)內(nèi)一律沒(méi)大公司在用,都非主流,排斥英文文檔和新技術(shù),以及各種超出他學(xué)習(xí)能力范圍的技術(shù)。 在撰寫(xiě)此文前首先必須申明的是本人不鄙視任何一種框架,也無(wú)意于挑起PHP框架間的戰(zhàn)爭(zhēng),更沒(méi)有貶低某個(gè)框架使用者的用意,本文純粹個(gè)人的看法。你可以認(rèn)為我無(wú)知也好,或者裝逼也好,請(qǐng)不要試著在任何情況下,隨便發(fā)起言語(yǔ)的...
摘要:開(kāi)發(fā)負(fù)責(zé)人創(chuàng)建分支,編寫(xiě)單元測(cè)試腳本,編寫(xiě)代碼,實(shí)現(xiàn)提案中的所有內(nèi)容,最終發(fā)起交叉評(píng)審,檢查代碼,提出改進(jìn)意見(jiàn),反饋給開(kāi)發(fā)負(fù)責(zé)人,繼續(xù)完善細(xì)節(jié)。 Swoole開(kāi)源項(xiàng)目從2012年開(kāi)始發(fā)布第一個(gè)版本,到現(xiàn)在已經(jīng)有近7年的歷史。在這七年的時(shí)間里: 提交了8821次代碼變更 發(fā)布了287個(gè)版本 收到并解決1161次issue反饋 合并了603次pull request 共有100位開(kāi)發(fā)者...
摘要:入門(mén),第一個(gè)這是一門(mén)很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...
閱讀 1328·2021-09-22 15:00
閱讀 3320·2019-08-30 14:00
閱讀 1235·2019-08-29 17:27
閱讀 1231·2019-08-29 16:35
閱讀 705·2019-08-29 16:14
閱讀 2051·2019-08-26 13:43
閱讀 2133·2019-08-26 11:35
閱讀 2317·2019-08-23 15:34