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