在我們實現(xiàn)自動調(diào)度(器)函數(shù)前,我們先來理解下高階函數(shù)
thunk函數(shù)# 先求值再傳參function func(m){ return m * 2; f(x + 5);// 等同于# 先傳參再求值var thunk = function () { return x + 5;function func(thunk){ return thunk() * 2;# 這段我們在python或一些語言里,概念叫高階函數(shù)# 因為php是解釋性動態(tài)語言,所以函數(shù)可以當(dāng)參數(shù)傳入# 這里python,js,php下函數(shù)都是可以傳參的PHP版本的thunkify函數(shù)
thunkify實現(xiàn)原理:
1、包裝一次原始函數(shù)名,然后返回一個第一次匿名函數(shù)(并攜帶包裝函數(shù)): return function () use ($func){$args = func_get_args();}
2、然后再獲取該匿名函數(shù)的參數(shù),并在上一次第一次匿名函數(shù)體內(nèi)返回一次帶回調(diào)參數(shù)的第二次匿名函數(shù)(并攜帶上一次環(huán)境上下文): return function ($callback) use ($args, $func){}
3、調(diào)用包裝函數(shù),參數(shù)為:第一次匿名函數(shù)調(diào)用的參數(shù)+一個回調(diào)函數(shù)
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { array_push($args, $callback); return $func(...$args);$printStr = function($p1, $p2, $callback) { $callback($p1, $p2);$printStrThunkify = thunkify($printStr);$printStrThunkify(...[ foo , bar ])(function (...$p) { var_dump($p);# outputarray(2) { [0]= string(3) foo [1]= string(3) bar }只能執(zhí)行一次回調(diào)的thunkify函數(shù)
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { // 原本的獲取參數(shù),回調(diào)會多次執(zhí)行 // array_push($args, $callback); // 增加回調(diào)只能執(zhí)行一次 $callbackCalled = false; array_push($args, function (...$params) use ($callback, $callbackCalled) { if ($callbackCalled) return ; $callbackCalled = true; $callback(...$params); return $func(...$args);$printStr = function($p1, $p2, $callback) { $callback($p1, $p2); $callback($p1, $p2); //我們增加一次回調(diào)$printStrThunkify = thunkify($printStr);$printStrThunkify(...[ foo , bar ])(function (...$p) { var_dump($p);# outputarray(2) { [0]= string(3) foo [1]= string(3) bar }
看到這里,你可能還在疑惑,thunkify函數(shù)其實只是幫我們包裝了一次有回調(diào)函數(shù)的高階函數(shù)而已
不過這里到底有什么用處呢,在普通場景下確實用戶不大(可能用處單純就在做一些前后置函數(shù)包裝也是用處的,類似python的裝飾)
但是,但是,但是在生成器協(xié)程里,Thunkify函數(shù)可以用于生成器協(xié)程的自動流程管理。
每一次yield出來的結(jié)果都是一個thunk函數(shù)的回調(diào)
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { $callbackCalled = false; array_push($args, function (...$params) use ($callback, $callbackCalled) { if ($callbackCalled) return ; $callbackCalled = true; $callback(...$params); return $func(...$args);$printStr1 = function($p1, $callback) { $callback($p1);$printStr2 = function($p1, $callback) { $callback($p1);$printStrThunkify1 = thunkify($printStr1);$printStrThunkify2 = thunkify($printStr2);function gen() global $printStrThunkify1, $printStrThunkify2; $r1 = yield $printStrThunkify1( 1 var_dump($r1); $r2 = yield $printStrThunkify2( 2 var_dump($r2);$gen = gen();// 手動回調(diào), 模擬自動執(zhí)行基礎(chǔ)理解$html' target='_blank'>value = $gen- current();$value(function ($p1) use($gen) { $value = $gen- send($p1); $value(function ($p1) use($gen) { $value = $gen- send($p1); var_dump($value);});自動執(zhí)行器
我們這里只是實現(xiàn)上面的手動回調(diào)執(zhí)行
增加了一個自動執(zhí)行器,把生成器協(xié)程傳入后講自動執(zhí)行生成器協(xié)程
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { $callbackCalled = false; array_push($args, function (...$params) use ($callback, $callbackCalled) { if ($callbackCalled) return ; $callbackCalled = true; $callback(...$params); return $func(...$args);$printStr1 = function($p1, $callback) { sleep(2); $callback($p1);$printStr2 = function($p1, $callback) { sleep(5); $callback($p1);$printStrThunkify1 = thunkify($printStr1);$printStrThunkify2 = thunkify($printStr2);function gen() global $printStrThunkify1, $printStrThunkify2; $r1 = yield $printStrThunkify1( 1 var_dump($r1); $r2 = yield $printStrThunkify2( 2 var_dump($r2);function autoCaller(/Generator $gen) // 注意這里的$next use 引入作用域必須帶上 , 否則無法識別 $next = function ($p1) use ($gen, $next) { if (is_null($p1)) { //此處獲取第一次yeild的回調(diào) $result = $gen- current(); } else { // send后返回的是下一次的yield值 $result = $gen- send($p1); // 是否生成器迭代完成 // 迭代器生成完成,不再迭代執(zhí)行(自動執(zhí)行器返回停止) if (!$gen- valid()) { return ; $result($next); $next(null);$gen1 = gen();//$gen2 = gen();autoCaller($gen1);//autoCaller($gen2);# outputstring(1) 1 string(1) 2 # 如果我們打開上面的兩個sleep()注釋# output# 等待2秒string(1) 1 # 等待5秒string(1) 2 # 因為這里我們的thunk里執(zhí)行的實際函數(shù)是同步的代碼,所以整體是阻塞的后續(xù)代碼執(zhí)行的總結(jié)
只要執(zhí)行 autoCaller 函數(shù),生成器就會自動迭代完成。這樣一來,異步操作不僅可以寫得像同步操作,而且一行代碼就可以執(zhí)行。
Thunkify函數(shù)并不是 生成器協(xié)程 函數(shù)自動執(zhí)行的唯一方案。
因為自動執(zhí)行的關(guān)鍵是,必須有一種機制,自動控制 生成器協(xié)程 函數(shù)的流程,接收和交還程序的執(zhí)行權(quán)。
回調(diào)函數(shù)可以做到這一點,Promise 對象也可以做到這一點。
以上就是PHP協(xié)程的thunkify自動執(zhí)行器的詳細(xì)介紹(代碼)的詳細(xì)內(nèi)容,PHP教程
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。
新聞熱點
疑難解答
圖片精選