摘要:超過三個參數會導致參數之間的組合過多,你必須對每個多帶帶的參數測試大量不同的情況。拆分這些函數,可以讓代碼可重用性更高且更易測試。
函數參數不要超過兩個
限制函數的參數數量是非常重要的,因為它使你的函數更容易測試。超過三個參數會導致參數之間的組合過多,你必須對每個多帶帶的參數測試大量不同的情況。
沒有參數是最理想的情況,一個或兩個參數是可以接受的,三個以上則是應該避免的。這很重要的。如果你有兩個以上的參數,那么你的函數可能試圖做的太多,如果不是,你可能需要將一個高級別的對象傳當做參數傳進去。
Bad:
function createMenu($title, $body, $buttonText, $cancellable) { // ... }
Good:
class MenuConfig { public $title; public $body; public $buttonText; public $cancellable = false; } $config = new MenuConfig(); $config->title = "Foo"; $config->body = "Bar"; $config->buttonText = "Baz"; $config->cancellable = true; function createMenu(MenuConfig $config) { // ... }一個函數只做一件事
這是軟件工程中一個重要的原則。這會讓你的代碼清晰易懂以及易于復用。
Bad:
function emailClients($clients) { foreach ($clients as $client) { $clientRecord = $db->find($client); if ($clientRecord->isActive()) { email($client); } } }
Good:
function emailClients($clients) { $activeClients = activeClients($clients); array_walk($activeClients, "email"); } function activeClients($clients) { return array_filter($clients, "isClientActive"); } function isClientActive($client) { $clientRecord = $db->find($client); return $clientRecord->isActive(); }函數名要能說明它是做什么的
Bad:
class Email { //... public function handle() { mail($this->to, $this->subject, $this->body); } } $message = new Email(...); // 這是什么?一條消息的句柄?還是要寫一個文件?(讀者的疑問) $message->handle();
Good:
class Email { //... public function send() { mail($this->to, $this->subject, $this->body); } } $message = new Email(...); // 一目了然 $message->send();函數應該只做一層抽象
當你有多個層次的抽象時,你的函數就已經做的太多了。拆分這些函數,可以讓代碼可重用性更高且更易測試。
Bad:
function parseBetterJSAlternative($code) { $regexes = [ // ... ]; $statements = explode(" ", $code); $tokens = []; foreach ($regexes as $regex) { foreach ($statements as $statement) { // ... } } $ast = []; foreach ($tokens as $token) { // lex... } foreach ($ast as $node) { // parse... } }
Bad too:
我們從函數中遷出去了一些工作,但是 parseBetterJSAlternative() 函數還是很復雜,不可測試。
function tokenize($code) { $regexes = [ // ... ]; $statements = explode(" ", $code); $tokens = []; foreach ($regexes as $regex) { foreach ($statements as $statement) { $tokens[] = /* ... */; } } return $tokens; } function lexer($tokens) { $ast = []; foreach ($tokens as $token) { $ast[] = /* ... */; } return $ast; } function parseBetterJSAlternative($code) { $tokens = tokenize($code); $ast = lexer($tokens); foreach ($ast as $node) { // parse... } }
Good:
最好的解決方案是移除 parseBetterJSAlternative 函數的依賴
class Tokenizer { public function tokenize($code) { $regexes = [ // ... ]; $statements = explode(" ", $code); $tokens = []; foreach ($regexes as $regex) { foreach ($statements as $statement) { $tokens[] = /* ... */; } } return $tokens; } } class Lexer { public function lexify($tokens) { $ast = []; foreach ($tokens as $token) { $ast[] = /* ... */; } return $ast; } } class BetterJSAlternative { private $tokenizer; private $lexer; public function __construct(Tokenizer $tokenizer, Lexer $lexer) { $this->tokenizer = $tokenizer; $this->lexer = $lexer; } public function parse($code) { $tokens = $this->tokenizer->tokenize($code); $ast = $this->lexer->lexify($tokens); foreach ($ast as $node) { // parse... } } }不要使用標志作為函數的參數
當你在函數中使用標志來作為參數時,你的函數就不是只做一件事情了,這與我們前面所講的每個函數只做一件事的原則相違背,所以不要使用標志作為函數的參數。
Bad:
function createFile($name, $temp = false) { if ($temp) { touch("./temp/".$name); } else { touch($name); } }
Good:
function createFile($name) { touch($name); } function createTempFile($name) { touch("./temp/".$name); }避免副作用
如果一個函數做了“拿到一個值并返回一個值或者多個值”以外的事情,那么這個函數就有可能產生副作用,副作用可能是意外的寫入了文件、修改了全局變量、或者打錢給了陌生人。
現在假如你確實要在函數中做一些有可能產生副作用的事情。 比如要寫一個文件,你需要做的是將寫文件的操作集中到一處,而不是在幾個函數或者類里對同一個文件做操作,實現一個服務(函數或者類)去操作它,有且僅有一個。
關鍵是要能避免常見的陷阱:像是在沒有結構的對象之間共享狀態、使用可能被寫入任何值的可變數據類型、 不集中處理有可能產生副作用的操作。 如果你能做到這些,你會比絕大多數程序員更快樂。
Bad:
// Global variable referenced by following function. // If we had another function that used this name, now it"d be an array and it could break it. $name = "Ryan McDermott"; function splitIntoFirstAndLastName() { global $name; $name = explode(" ", $name); } splitIntoFirstAndLastName(); var_dump($name); // ["Ryan", "McDermott"];
Good:
function splitIntoFirstAndLastName($name) { return explode(" ", $name); } $name = "Ryan McDermott"; $newName = splitIntoFirstAndLastName($name); var_dump($name); // "Ryan McDermott"; var_dump($newName); // ["Ryan", "McDermott"];不要修改全局變量
在許多編程語言中污染全局是一種糟糕的做法,因為你的庫可能會與另一個庫沖突,但是你的庫的用戶卻一無所知,直到在生產環境中爆發異常。讓我們來考慮一個例子:如果你想要拿到配置數組怎么辦?你可以編寫全局函數,如config(),但是它可能與另一個試圖做同樣事情的庫沖突。
Bad:
function config() { return [ "foo" => "bar", ] }
Good:
class Configuration { private $configuration = []; public function __construct(array $configuration) { $this->configuration = $configuration; } public function get($key) { return isset($this->configuration[$key]) ? $this->configuration[$key] : null; } } $configuration = new Configuration([ "foo" => "bar", ]);避免條件判斷
人們會問“如果不用 if 語句我該怎么做?”,答案是在許多情況下,你可以用多態來實現同樣的效果。那這樣做什么好處,還是那句話:“一個函數應該只做一件事”, 當你的類或函數中有了 if 語句,你的函數就不止是只做一件事情了。
Bad:
class Airplane { // ... public function getCruisingAltitude() { switch ($this->type) { case "777": return $this->getMaxAltitude() - $this->getPassengerCount(); case "Air Force One": return $this->getMaxAltitude(); case "Cessna": return $this->getMaxAltitude() - $this->getFuelExpenditure(); } } }
Good:
interface Airplane { // ... public function getCruisingAltitude(); } class Boeing777 implements Airplane { // ... public function getCruisingAltitude() { return $this->getMaxAltitude() - $this->getPassengerCount(); } } class AirForceOne implements Airplane { // ... public function getCruisingAltitude() { return $this->getMaxAltitude(); } } class Cessna implements Airplane { // ... public function getCruisingAltitude() { return $this->getMaxAltitude() - $this->getFuelExpenditure(); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/25949.html
摘要:將代碼寫的簡潔并且易讀易懂是每一位優秀的所應該具備的基本功。前幾天在上看到這個項目,感覺很有收獲,于是在這里記錄一下。 將代碼寫的簡潔并且易讀易懂是每一位優秀的coder所應該具備的基本功。 前幾天在github上看到clean-code-php這個項目,感覺很有收獲,于是在這里記錄一下。 使用有意義并且可讀的變量名稱 Bad: $ymdstr = $moment->format(y-...
摘要:使用和在中,通過為屬性或方法設置和關鍵字可以實現對屬性或方法的可見性控制。你的繼承表達了一個對等比如人類是動物的關系,不是包含的關系比如用戶具有用戶詳情你能從基類中復用代碼你想通過修改全局類來對所有派生類進行修改。 使用getter和setter 在 PHP 中,通過為屬性或方法設置 public, protected 和 private 關鍵字可以實現對屬性或方法的可見性控制。不過,...
摘要:統一的編碼規范編碼規范往簡單說其實就是三個方面換行空格變量命名放在里面,還有一些附加的地方,比如關鍵字大小寫,語法糖的使用與等的問題。這些都是規范代碼的重要手段。推廣給你的隊友團隊項目中,隊友的配合對整個代碼的規范起著決定性的作用。 1. 統一的編碼規范 編碼規范往簡單說其實就是三個方面: 換行 空格 變量命名 放在 PHP 里面,還有一些附加的地方,比如關鍵字大小寫,語法糖的使用...
摘要:是推薦的便于記憶的首字母簡寫,它代表了命名的最重要的五個面對對象編碼設計原則單一職責原則開閉原則里氏替換原則接口隔離原則依賴反轉原則單一職責原則修改一個類應該只為一個理由。別寫重復代碼這條原則大家應該都是比較熟悉了。 SOLID 是Michael Feathers推薦的便于記憶的首字母簡寫,它代表了Robert Martin命名的最重要的五個面對對象編碼設計原則 S: 單一職責原則 ...
摘要:考慮到函數表示某種行為,函數名稱應該是動詞或短語,用以說明其背后的意圖以及參數的意圖。不好的方式好的方式使用條件簡寫。這可能微不足道,但值得一提。 為了保證可讀性,本文采用的音譯而非直意。 簡介 如果你關注代碼本身和代碼的編寫方式,而不是只關心它是否能工作,那么你寫代碼是有一定的水準。專業開發人員將為未來的自己和其他人編寫代碼,而不僅僅只編寫當前能工作就行的代碼。 在此基礎上,簡潔代碼...
閱讀 847·2021-11-25 09:43
閱讀 3681·2021-11-19 09:40
閱讀 882·2021-09-29 09:34
閱讀 1783·2021-09-26 10:21
閱讀 870·2021-09-22 15:24
閱讀 4187·2021-09-22 15:08
閱讀 3265·2021-09-07 09:58
閱讀 2656·2019-08-30 15:55