深入PHP函數式編程:探秘Transducers
你可能聽說過函數式編程和高階函數,但你了解Transducers嗎?本文將帶你探索這個強大的數據轉換工具。
核心要點:
Transducers定義
要理解Transducers,首先需要了解約簡器(Reducers)。引用Rich Hickey的話:
一個約簡函數正是你傳遞給
reduce
的函數類型——它接收迄今為止的結果和一個新的輸入,並返回下一個迄今為止的結果。
一個Transducer是一個函數,它接收一個約簡函數並返回另一個約簡函數。
Transducers最初由Rich Hickey引入Clojure,並由Michael Dowling移植到PHP。 Transducers是構建可在多種情況下重用的算法轉換的強大方法。本文將通過一系列實際示例來探討其用途。
示例
在繼續之前,我們需要通過Composer安裝Transducers包。
composer require mtdowling/transducers
我們將為以下示例使用一個簡單的User類。
class User { public $id; public $name; public $age; public function __construct($id, $name, $age) { $this->id = $id; $this->name = $name; $this->age = $age; } public function __toString() { return sprintf("\n%d - %s - %d", $this->id, $this->name, $this->age); } } // 示例数据 $data = [ new User(1, "younes", 24), new User(2, "youssef", 26), new User(3, "hamza", 25), new User(4, "ismail", 17), ];
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\xform($data, $uppercase); var_dump($result);
map
函數類似於PHP的array_map
函數:我們傳遞一個可調用函數,在本例中,它將把用戶名首字母大寫。
我們使用xform
函數應用我們的uppercase
Transducer。它將我們的數據作為第一個參數,Transducer作為第二個參數。
// 输出 array(4) { [0]=> object(User)#14 (3) { ["id"]=> int(1) ["name"]=> string(6) "Younes" ["age"]=> int(24) } [1]=> object(User)#15 (3) { ["id"]=> int(2) ["name"]=> string(7) "Youssef" ["age"]=> int(26) } [2]=> object(User)#16 (3) { ["id"]=> int(3) ["name"]=> string(5) "Hamza" ["age"]=> int(25) } [3]=> object(User)#17 (3) { ["id"]=> int(4) ["name"]=> string(6) "Ismail" ["age"]=> int(17) } }
xform
返回與數據參數相同類型的值(在本例中為數組)。如果嚴格需要輸出數組,我們也可以使用to_array
。
// ... $result = t\to_array($data, $uppercase); // ...
我們也可以使用to_string
將輸出轉換為字符串,或者使用into($target, $coll, callable $xf)
將輸出轉換為特定類型。更多細節請查看文檔。
composer require mtdowling/transducers
class User { public $id; public $name; public $age; public function __construct($id, $name, $age) { $this->id = $id; $this->name = $name; $this->age = $age; } public function __toString() { return sprintf("\n%d - %s - %d", $this->id, $this->name, $this->age); } } // 示例数据 $data = [ new User(1, "younes", 24), new User(2, "youssef", 26), new User(3, "hamza", 25), new User(4, "ismail", 17), ];
Transducers最棒的部分是我們可以將多個轉換組合成一個Transducer。例如,讓我們將用戶名的首字母大寫並刪除未成年人。
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\xform($data, $uppercase); var_dump($result);
filter
函數類似於PHP的array_filter
函數。 comp
函數從Transducer列表創建一個Transducer,在本例中為uppercase
(使用map
)和removeMinors
(使用filter
)。
// 输出 array(4) { [0]=> object(User)#14 (3) { ["id"]=> int(1) ["name"]=> string(6) "Younes" ["age"]=> int(24) } [1]=> object(User)#15 (3) { ["id"]=> int(2) ["name"]=> string(7) "Youssef" ["age"]=> int(26) } [2]=> object(User)#16 (3) { ["id"]=> int(3) ["name"]=> string(5) "Hamza" ["age"]=> int(25) } [3]=> object(User)#17 (3) { ["id"]=> int(4) ["name"]=> string(6) "Ismail" ["age"]=> int(17) } }
現在我們有一個可重用的Transducer組合,我們可以隨時使用它來根據此標準約簡數據。查看文檔以了解可用約簡函數的列表。
創建Transducer
約簡函數接收一個值作為參數,並返回一個約簡函數數組,該數組必須包含三個元素:
init
:返回Transducer初始值的函數。如果未提供初始值,則僅在第一次調用時調用。 result
:result
函數用於根據調用棧構建最終結果。 step
:這是你編寫約簡邏輯的地方——根據你的約簡邏輯,你可能調用它零次或多次。 如果沒有實際代碼,這會變得非常混亂,因此讓我們以take
Transducer函數為例。它從數據數組頂部獲取n個項目。
// ... $result = t\to_array($data, $uppercase); // ...
use Transducers as t; $uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $result = t\to_string($data, $uppercase); var_dump($result);
以下是take
約簡函數的源代碼。
// 输出 string(64) " 1 - Younes - 24 2 - Youssef - 26 3 - Hamza - 25 4 - Ismail - 17"
take
函數被多次調用,帶有result
和input
參數。每次調用時,它都會遞減remaining
變量並測試它是否小於零。在這種情況下,我們返回一個Reduced
對象實例,這表示一個停止點。
我們的Transducer函數示例將從數據中刪除空元素。使用前面關於Transducer工作原理的解釋,我們可以訪問$input
變量,並決定是調用下一個step
回調還是簡單地返回值。
$uppercase = t\map(function($user) { return new User($user->id, ucfirst($user->name), $user->age); }); $removeMinors = t\filter(function($user) { return $user->age >= 18; }); $comp = t\comp( $uppercase, $removeMinors ); $result = t\to_string($data, $comp); var_dump($result);
我們可以通過向我們的$data
變量添加一些空項目來測試這一點。
// 输出 string(48) " 1 - Younes - 24 2 - Youssef - 26 3 - Hamza - 25"
// .... $comp = t\comp( $uppercase, $removeMinors, t\take(2) ); $result = t\to_string($data, $comp); var_dump($result);
結論
在本文中,我們了解了函數式編程世界的一個新方面,稱為Transducers。我們回顧了Transducers的目的,即使數據轉換更容易。我們還回顧了一些示例,以更好地演示Transducers的價值。你現在在你的開發者工具箱中擁有了一個新的工具,或者至少對Transducer的概念有了更好的理解。
如果你對Transducers有任何疑問,可以在下面發表!
PHP中Transducers的常見問題
PHP中的Transducers是一種數據處理技術,允許你創建可組合和可重用的軟件組件。它們本質上是接受一個約簡器並返回一個新約簡器的函數。這個概念借鑒自Clojure和JavaScript,並已適應PHP。 Transducers允許你將數據轉換過程與實際數據源分離,使你的代碼更模塊化、更易於維護。
傳統的PHP函數通常將獲取數據和轉換數據的過程結合在一起,這可能導致難以維護和重用的代碼。另一方面,Transducers將這兩個過程分開。這意味著你可以創建一個以特定方式轉換數據的Transducer,然後將其與任何數據源一起使用,使你的代碼更靈活、更可重用。
當然,讓我們考慮一個簡單的示例。假設你有一個數字數組,並且你想將每個數字加1。你可以創建一個執行此操作的Transducer:
composer require mtdowling/transducers
然後,你可以將此Transducer與任何約簡函數和數據源一起使用。
Transducers設計用於與任何數據源一起使用。這是因為它們在單個數據項級別運行,而不是在整個數據源級別運行。因此,你可以將Transducer與數組、數據庫查詢結果、來自網絡連接的數據流等一起使用。唯一的要求是你的數據源必須能夠與約簡函數一起工作。
Transducers提供了許多好處。它們允許你將數據轉換過程與實際數據源分離,使你的代碼更模塊化、更易於維護。它們還允許你創建可重用的軟件組件,可用於任何數據源。最後,因為Transducers操作單個數據項,所以在處理大型數據集時,它們可能比傳統的PHP函數更高效。
雖然Transducers提供了許多好處,但它們也可能比傳統的PHP函數更複雜。這是因為它們涉及函數式編程的概念,這些概念對一些PHP開發人員來說可能不熟悉。但是,一旦你理解了Transducers的工作原理,它們就可以成為編寫乾淨、高效和可重用代碼的強大工具。
是的,Transducers可以與任何PHP框架一起使用。它們是一種通用的數據處理技術,不依賴於任何特定的框架特性。但是,一些框架可能提供自己用於處理Transducers的實用程序,這可以使它們更容易使用。
有很多資源可用於學習PHP中的Transducers。你可以從閱讀網上的文章和教程開始,例如SitePoint上的文章。還有一些書籍和在線課程更深入地介紹了這個主題。最後,你可以嘗試編寫自己的Transducers並在你的PHP項目中使用它們。
是的,Transducers的概念起源於Clojure編程語言,此後已被其他幾種語言採用,包括JavaScript和PHP。每種語言都以自己的方式實現Transducers,但基本概念是相同的。
是的,你可以將Transducers與PHP內置的數組函數一起使用。但是,請記住,這些函數可能不如使用Transducer高效,尤其是在處理大型數組時。這是因為PHP的數組函數通常會創建新的數組,而Transducer可以在原地轉換數據。
以上是PHP中的傳感器變得容易的詳細內容。更多資訊請關注PHP中文網其他相關文章!