摘要:函數(shù)式編程不是一個(gè)框架或工具,而是一種編寫代碼的方式。函數(shù)式編程首先是一個(gè)聲明式編程范例。舉個(gè)例子純函數(shù)函數(shù)式編程基于的前提是您將基于純函數(shù)構(gòu)建不可變的程序作為業(yè)務(wù)邏輯的構(gòu)建塊。
PHP 新版本的解讀最近朋友推薦這本書:Functional PHP ,很多對(duì)于程序設(shè)計(jì)方面的思路值得多思考和借鑒。函數(shù)式編程不是一個(gè)框架或工具,而是一種編寫代碼的方式。FP 是一種軟件開發(fā)風(fēng)格,主要強(qiáng)調(diào)功能的使用,個(gè)人覺得對(duì)于重構(gòu)代碼很有幫助。書中也談到了例如 PHP5.3 中引入的閉包函數(shù)和高階函數(shù),在實(shí)際開發(fā)過程中善于活學(xué)活用也是函數(shù)式的靈魂所在。
增加了嚴(yán)格的鍵入和標(biāo)量類型聲明類型聲明允許你用合適的類或標(biāo)量類型( boolean,integer,string,MyClass 等)限定任何函數(shù)參數(shù)。這些在PHP 5中被部分支持為“類型提示”,但沒有標(biāo)量支持。在PHP 7中,你也可以聲明函數(shù)返回值的類型。
作為一種動(dòng)態(tài)語言,PHP 將總是試圖將錯(cuò)誤類型的值強(qiáng)制轉(zhuǎn)換為期望的標(biāo)量類型。
例如,當(dāng)給定一個(gè)字符串時(shí),需要一個(gè)整數(shù)參數(shù)的函數(shù)將強(qiáng)制該值為一個(gè)整數(shù),文件頂部引用強(qiáng)制類型檢測(cè)模式
declare(strict_types=1);
參數(shù)異常會(huì)拋出如下錯(cuò)誤e
PHP Warning: Uncaught TypeError: Argument 1 passed to increment() must be of the type integer, string given...聲明性編碼
感覺翻譯后的理解很模糊,看例子可能會(huì)更加清晰透徹一點(diǎn)。“函數(shù)式編程首先是一個(gè)聲明式編程范例。這意味著它們表達(dá)了操作的邏輯連接,而不會(huì)泄露它們是如何實(shí)現(xiàn)的,或者數(shù)據(jù)如何實(shí)際流經(jīng)它們,它著重于使用表達(dá)式來描述程序的邏輯是什么”
在 PHP 中,聲明性代碼是使用高階函數(shù)來實(shí)現(xiàn)的,個(gè)人覺得作者的意思還是靈活運(yùn)用系統(tǒng)內(nèi)置函數(shù)處理邏輯,放棄復(fù)雜而不簡潔的邏輯控制,代碼越復(fù)雜,重構(gòu)越麻煩,bug率更高。一個(gè)簡單的例子走一個(gè)。
// method 1 $array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for($i = 0; $i < count($array); $i++) { $array[$i] = pow($array[$i], 2); } print_r($array); //-> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] // method 2 $square = function (int $num): int { return pow($num, 2); }; print_r(array_map($square, $array)) // q: 結(jié)果累加 function add(float $a, float $b): float { return $a + $b; } print_r(array_reduce(array_map($square, $array), "add")); //-> 285設(shè)計(jì)為不變性和無狀態(tài)
例如是上面的例子中使用的 array_map ,好處在于它不可變,也就是說不會(huì)改變?cè)紨?shù)組的內(nèi)容,使用不可變變量進(jìn)行編碼好處如下:
程序出現(xiàn)異常的主要原因之一是對(duì)象的狀態(tài)無意中改變,或者其引用變?yōu)榭?。不可變?duì)象可以傳遞給任何函數(shù),它們的狀態(tài)將始終保持不變。
不可變的數(shù)據(jù)結(jié)構(gòu)在共享內(nèi)存多線程應(yīng)用程序中非常重要。在本書中,我們不會(huì)多談關(guān)于并發(fā)處理的問題,因?yàn)?PHP 進(jìn)程大部分是孤立運(yùn)行的。現(xiàn)在,無論是否設(shè)計(jì)并行性,無狀態(tài)對(duì)象都是在許多常見PHP部署中廣泛使用的模式。例如,作為最佳實(shí)踐,Symfony 服務(wù)(或服務(wù)對(duì)象)應(yīng)該始終是無狀態(tài)的。一個(gè)服務(wù)不應(yīng)該持續(xù)任何狀態(tài),并提供一組臨時(shí)函數(shù),它們將處理它所在的域,執(zhí)行某種業(yè)務(wù)邏輯的計(jì)算,并返回結(jié)果。
PHP 對(duì)于不可變變量的支持很差,實(shí)際開發(fā)過程中使用常量定義 define const 關(guān)鍵字。對(duì)于 define 和 const 的比較。const 在編譯時(shí)定義,這意味著編譯器可以聰明地存儲(chǔ)它們,但是你不能有條件地聲明。用 define 聲明的常量是多功能和動(dòng)態(tài)的。因?yàn)榫幾g器不會(huì)嘗試為它們分配空間,直到它真正看到它們。defined($name) 在使用它的值之前,你應(yīng)該經(jīng)常檢查是否定義了一個(gè)常量 constant($name)。舉個(gè)例子
// error : throw exception if (純函數(shù)) { const C1 = "FOO"; } else { const C2 = "BAR"; } // ok normal if ( ) { define("C1", "FOO") } else { define("C2", "BAR") }
高階 PHP函數(shù)式編程基于的前提是您將基于純函數(shù)構(gòu)建不可變的程序作為業(yè)務(wù)邏輯的構(gòu)建塊。
關(guān)于高階函數(shù)和閉包本書都會(huì)提到,高階函數(shù)被定義為可以接受其他函數(shù)作為參數(shù)或返回其他函數(shù)的函數(shù)。當(dāng)然函數(shù)可以分配給變量。
PHP 中的函數(shù)可以像對(duì)象一樣進(jìn)行操作。事實(shí)上,如果你要檢查一個(gè)函數(shù)的類型,你會(huì)發(fā)現(xiàn)它們是Closure
的實(shí)例。將一個(gè)函數(shù)賦予給一個(gè)變量這個(gè)在實(shí)際應(yīng)用中很常見。例如下面的例子
$str = function (string $str1, string $str2) { return $str1 . " " . $str2; } $str("hello", "word"); // output hello word; is_callable($str) // 1
這個(gè)代碼使用匿名函數(shù)(RHS)并將其分配給變量 $str(LHS)。或者,您可以使用 is_callable() 來檢查是否存在函數(shù)變量
函數(shù)也可以從其他函數(shù)返回。這是創(chuàng)建函數(shù)族的非常有用的技巧。
function concatWith(string $a): callable { return function (string $b) use ($a): string { return $a . $b; }; } $helloWith = concatWith("Hello"); $helloWith("World"); // output -> "Hello World"
提供函數(shù)作為參數(shù), 創(chuàng)建了一個(gè)簡單的函數(shù),它接受一個(gè)可調(diào)用的函數(shù)并將其應(yīng)用于其他參數(shù)
function apply(callable $operator, $a, $b) { return $operator($a, $b); } $add = function (float $a, float $b): float { return $a + $b; }; apply($add, 1, 2); // output -> 3 // or power function apply(callable $operator): callable { return function($a, $b) use ($operator) { return $operator($a, $b); }; } apply($add)(5, 5); //output -> 10 $adder = apply($add); $adder(5, 5) // output -> 10
遇到另外一種情況,也就是兩個(gè)數(shù)相除分母不能為0,這個(gè)時(shí)候構(gòu)建一個(gè)空檢查函數(shù)會(huì)比較好,時(shí)刻檢查變量的值是個(gè)好習(xí)慣。
function safeDivide(float $a, float $b): float { return empty($b) ? NAN : $a / $b; } apply($safeDivide)(5, 0); //-> NAN $result = apply($safeDivide)(5, 0); if(!is_nan($result)) { return $result; } else { Log::warning("Math error occurred! Division by zero!"); }
“這種方法避免了拋出一個(gè)異常?;叵胍幌聮伄惓5那闆r,它會(huì)導(dǎo)致程序堆棧展開和記錄寫入,但也不尊重代碼的局部性原則。尤其是它不服從空間地域性,它指出應(yīng)該依次執(zhí)行的相關(guān)陳述應(yīng)該相互靠近。這在 CPU 架構(gòu)上有更多的應(yīng)用,但也可以應(yīng)用于代碼設(shè)計(jì)?!边@種翻譯型的語句我還是日后在理解吧,說不定有一天就豁然開朗了,畢竟這是一條很遙遠(yuǎn)的路。
PHP 還通過可調(diào)用的對(duì)象將其提升到了一個(gè)新的水平?,F(xiàn)在,這不是一個(gè)真正的功能概念,但正確使用它可能是一個(gè)非常強(qiáng)大的技術(shù)。事實(shí)上,引擎蓋下的 PHP 匿名函數(shù)語法被編譯成一個(gè)類,并且有一個(gè)invoke() 方法。查資料的釋義就是調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí)的回應(yīng)方法
class Demo { private $collect; public function __construct($num) { $this->collect = $num; } public function increment() : int { return ++$this->collect; } public function __invoke() { return $this->increment(); } } $demo = new Demo(1); echo $demo(); // output -> 2使用容器改善api
使用包裝來控制對(duì)特定變量的訪問并提供額外的行為。先看下例子中的這個(gè) class ,下面的例子擴(kuò)展性較強(qiáng)
class Container { private $_value; private function __construct($value) { $this->_value = $value; } // Unit function public static function of($val) { return new static($val); } // Map function public function map(callable $f) { return static::of(call_user_func($f, $this->_value)); } // Print out the container public function __toString(): string { return "Container[ {$this->_value} ]"; } // Deference container public function __invoke() { return $this->_value; } }
function container_map(callable $f, Container $c): Container { return $c->map($f); }
$c = Container::of(" Hello FP >")->map("htmlspecialchars")->map("strtolower"); $c; //output-> Container[ hello fp > ]關(guān)閉
在 PHP 5.4+之后,PHP中的所有函數(shù)都是從 Closure 類創(chuàng)建的對(duì)象。使用RFC可以使代碼更加簡潔明了
function addTo($a) { return function ($b) use ($a) { return $a + $b; }; } $filter = function (callable $f): Container { return Container::of(call_user_func($f, $this->_value) ? $this->_value : 0); }; $wrappedInput = Container::of(2); $validatableContainer = $filter->bindTo($wrappedInput, Container); $validatableContainer("is_numeric")->map(addTo(40)); // output-> 42 $wrappedInput = Container::of("abc); $validatableContainer("is_numeric")->map(addTo(40)); // output-> 40說明
關(guān)于這本書的詳細(xì)內(nèi)容和例子戳鏈接 Functional PHP,關(guān)于 函數(shù)式編程的 composer 包 Functional PHP: Functional primitives for PHP
{ "require": { "lstrojny/functional-php": "~1.2" } }
本質(zhì)上這本書我還沒有看完,翻譯起來很多地方確實(shí)詞不達(dá)意,我還是根據(jù)實(shí)際的舉例逐個(gè)去理解的,此文章后續(xù)還會(huì)繼續(xù)補(bǔ)充和追加學(xué)習(xí)心得。 Go PHP!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/26215.html
摘要:函數(shù)對(duì)象連接到。好處有助于確保全局名字空間的純凈性私有性保留了自己的函數(shù),不為外部應(yīng)用程序所用返回自己的函數(shù)函數(shù)始終有一個(gè)返回值,即便不是顯示返回,它們會(huì)隱式返回一個(gè)。 函數(shù) 概念: 函數(shù)包含一組語句,它們是javaScript基礎(chǔ)模塊單元,用于代碼復(fù)用、信息隱藏和組合調(diào)用。用于指定對(duì)象的行為。 函數(shù)對(duì)象: javascrtipt中的函數(shù)就是對(duì)象。對(duì)象是‘名/值’對(duì)的集合并擁有一個(gè)連...
摘要:反對(duì)者在某些領(lǐng)域?qū)Υ擞枰苑裾J(rèn)。下面再引用一段來自維基百科中關(guān)于的歷史。類的更嚴(yán)格的定義是由某種特定的元數(shù)據(jù)所組成的內(nèi)聚的包。類還可以有運(yùn)行時(shí)表示形式元對(duì)象,它為操作與類相關(guān)的元數(shù)據(jù)提供了運(yùn)行時(shí)支持。 在開始部分,請(qǐng)看官非常非常耐心地閱讀下面幾個(gè)枯燥的術(shù)語解釋,本來這不符合本教程的風(fēng)格,但是,請(qǐng)看官諒解,因?yàn)榱形粚硪欢ㄒ喿x枯燥的東西的。這些枯燥的屬于解釋,均來自維基百科。 1、問題...
摘要:網(wǎng)絡(luò)編程就是如何在程序中實(shí)現(xiàn)兩臺(tái)計(jì)算機(jī)的通信。而網(wǎng)絡(luò)編程最終要開發(fā)出來的應(yīng)用大多數(shù)為支持各種協(xié)議的服務(wù)器,比如服務(wù)器服務(wù)器或者是基于自定義的協(xié)議實(shí)現(xiàn)的服務(wù)。在開始編碼之前,首先介紹一下協(xié)議棧上圖是我從網(wǎng)絡(luò)編程這本書拍下來的。 相信大部分的初中級(jí)PHP程序員平時(shí)寫的業(yè)務(wù)代碼占絕大多數(shù),寫厭了平時(shí)的增刪改查,何不體驗(yàn)體驗(yàn)網(wǎng)絡(luò)編程的魅力呢。 學(xué)習(xí)網(wǎng)絡(luò)編程能夠很好的理解一些底層的網(wǎng)絡(luò)通信,比如...
摘要:函子上面容器上定義了方法,的定義也類似是實(shí)現(xiàn)了函數(shù)并遵守一些特定規(guī)則的容器類型。不同類型的函子容器在處理內(nèi)部值時(shí),經(jīng)常遇到傳入?yún)?shù)異常的情況的情況,檢查值的合理性就非常重要。函子保證在調(diào)用傳入的函數(shù)之前,檢查值是否為空。 最近一直在學(xué)習(xí)函數(shù)式編程,前面介紹了函數(shù)式編程中非常重要的兩個(gè)運(yùn)算函數(shù)柯里化 和 函數(shù)組合,下文出現(xiàn)的curry 和 compose函數(shù)可以從前兩篇文章中找到。它們都...
閱讀 1583·2023-04-25 18:56
閱讀 1518·2021-09-29 09:34
閱讀 1741·2021-09-22 15:51
閱讀 3538·2021-09-14 18:03
閱讀 1202·2021-07-23 17:54
閱讀 2054·2019-08-29 18:38
閱讀 2934·2019-08-29 12:38
閱讀 641·2019-08-26 13:41