這篇文章的靈感很大程度上來自 Gina Banyard 在「FORUM PHP 2024」上的技術演講:
讓我們從一些同義詞開始:
如果你用谷歌搜尋“PHP monads”,其他概念會很快出現,例如函數式程式設計、綁定、堆疊,甚至深奧的數學(例如函子、廬半群)。
別怕。
從本質上講,Monad 是一種可以透過多種方式實現的模式。
當您要執行一些操作時,您可以像往常一樣簡單地定義自訂物件和助理。
那麼,為什麼要費心考慮替代概念呢?
恕我直言,這仍然是一個好問題,因為您需要保持效率,但經典方法有常見的限制:
Monad 可以更一致地處理可選(或尚未可用)值。
現代專案包含靜態分析工具,但 PHP 異常沒有類型化。
也就是說,工具無法偵測函數簽章中的異常,因此無法判斷程式碼是否正確處理異常。
為了測試這一點,開發團隊通常會編寫功能測試,但透過靜態分析進行早期檢測會更可靠。
來源:「Les Exception:le trou dans la raquette du typepage」(fr)
使用 Monads,您在所有情況下都會獲得一個類型化對象,例如自訂枚舉情況(例如 FileErrors::AccessDenied),因此錯誤會在系統中鍵入。
建立強大的日誌系統可能具有挑戰性。複製字串和呼叫很容易。
您可能會定義一個名為 log() 的自訂幫助程序,並在專案中的任何地方使用它,而不是對所有內容進行硬編碼。
這旨在保持程式碼乾燥,但可能不允許在特定情況下組合更複雜的函數。
函數式方法不包括使用這樣的全域幫助器。相反,它寧願實作一個 Monad 來包裝其他函數:
final class LoggerMonad { public function __construct( public mixed $data, public array $logs = [], ) {} public function bind(callable $fn) { $resultLoggerMonad = $fn($this->data); return new LoggerMonad( $resultLoggerMonad->data, [...$this->logs, ...$resultLoggerMonad->logs], ); } } function loggify(callable $fn): Closure { return function ($value) use ($fn) { $name = (new ReflectionFunction($fn))->name; $log = [ 'Running '. $name .'('. var_export($value, true) .')' ]; return new LoggerMonad($fn($value), $log); }; }
然後,您可以像這樣使用 loggify 包裝器:
function add2(int $v): int { return $v + 2; } function square(int $v): int { return $v * $v; } function multi3(int $v): int { return $v * 3; } function logIt($value, callable ...$fns) { $logging_fns = array_map(loggify(...), $fns); $monad = new LoggerMonad($value); foreach ($logging_fns as $fn) { $monad = $monad->bind($fn); } return $monad; } print_r(logIt( 3, add2(...), square(...), multi3(...) ));
來源:“Monades simplement”,作者:Gina Banyard (fr)
??寶貝別傷害我
Monad 旨在包裝值,可以是任何類型,包括物件和函數。
與任何其他包裝系統一樣,您會發現一個將此值作為輸入的構造函數(〜類)以及一些根據您嘗試實現的模式有其自己用途的方法。
但是,所有 Monad 都包含綁定函數。顧名思義,這是傳遞值(或回調)的地方。
無論這些回呼中發生什麼,monad 都會包裝它,這似乎是裝飾值和重構程式碼的強大方法。
這顯然取決於實現,一開始很容易迷失。
但是,這種替代方法可以顯著減少 if 區塊的數量,並使回傳值更一致:
final class LoggerMonad { public function __construct( public mixed $data, public array $logs = [], ) {} public function bind(callable $fn) { $resultLoggerMonad = $fn($this->data); return new LoggerMonad( $resultLoggerMonad->data, [...$this->logs, ...$resultLoggerMonad->logs], ); } } function loggify(callable $fn): Closure { return function ($value) use ($fn) { $name = (new ReflectionFunction($fn))->name; $log = [ 'Running '. $name .'('. var_export($value, true) .')' ]; return new LoggerMonad($fn($value), $log); }; }
來源:fp4php - monad
希望您現在對 PHP monad 有更多了解。
當然,您不應該僅僅為了專案而添加花哨的設計模式。
此外,雖然這是一個全新的範例,但很容易錯過要點並專注於非常具體的方面,例如錯誤處理。
然而,發現新方法仍然令人耳目一新。我們需要跳出框框思考。
以上是PHP:單子的詳細內容。更多資訊請關注PHP中文網其他相關文章!