Home > Article > Backend Development > Detailed introduction of thunkify automatic executor of PHP coroutine (code)
This article brings you a detailed introduction (code) about the thunkify automatic executor of PHP coroutine. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Before we implement the automatic scheduling (controller) function, let’s first understand the high-order function
# 先求值再传参 function func(m){ return m * 2; } f(x + 5); // 等同于 # 先传参再求值 var thunk = function () { return x + 5; }; function func(thunk){ return thunk() * 2; } # 这段我们在python或一些语言里,概念叫高阶函数 # 因为php是解释性动态语言,所以函数可以当参数传入 # 这里python,js,php下函数都是可以传参的
Thunkify implementation principle:
1. Wrap the original function name once, and then return a first anonymous function (and carry the wrapping function): return function () use ($func){$args = func_get_args();}
2, then get the parameters of the anonymous function, and return the second time with callback parameters in the body of the last first anonymous function Anonymous function (and carries the last environment context): return function ($callback) use ($args, $func){}
3. Call the wrapper function, the parameters are: the parameters of the first anonymous function call A callback function
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); }); # output array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" }
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { // 原本的获取参数,回调会多次执行 // array_push($args, $callback); // 增加回调只能执行一次 $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); //我们增加一次回调 }; $printStrThunkify = thunkify($printStr); $printStrThunkify(...["foo", "bar"])(function (...$p) { var_dump($p); }); # output array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" }
Seeing this, you may still be confused. The thunkify function actually just helps us wrap a high-level function with a callback function. It’s just a function
But what is the use here? In ordinary scenarios, there are indeed not many users (it may be used simply to wrap some pre- and post-function functions, similar to python decoration)
But, but, but In generator coroutine
, Thunkify function
can be used for automatic process management of generator coroutine
.
The result of each yield is a callback of a thunk function
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(); // 手动回调, 模拟自动执行基础理解 $value = $gen->current(); $value(function ($p1) use($gen) { $value = $gen->send($p1); $value(function ($p1) use($gen) { $value = $gen->send($p1); var_dump($value); }); });
Here we only implement the manual callback execution above
Added an automatic executor, and after passing in the generator coroutine, we will automatically execute the generator coroutine
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的回调 $result = $gen->current(); } else { // send后返回的是下一次的yield值 $result = $gen->send($p1); } // 是否生成器迭代完成 // 迭代器生成完成,不再迭代执行(自动执行器返回停止) if (!$gen->valid()) { return ; } $result($next); }; $next(null); } $gen1 = gen(); //$gen2 = gen(); autoCaller($gen1); //autoCaller($gen2); # output string(1) "1" string(1) "2" # 如果我们打开上面的两个sleep()注释 # output # 等待2秒 string(1) "1" # 等待5秒 string(1) "2" # 因为这里我们的thunk里执行的实际函数是同步的代码,所以整体是阻塞的后续代码执行的
As long as the execution autoCaller
function, the generator will automatically iterate to complete. In this way, asynchronous operations can not only be written like synchronous operations, but can also be executed in one line of code.
Thunkify function is not the only solution for automatic execution of generator coroutine
function.
Because the key to automatic execution is that there must be a mechanism to automatically control the flow of the generator coroutine
function and receive and return the execution right of the program.
The callback function can do this, and the Promise object can also do this.
The above is the detailed content of Detailed introduction of thunkify automatic executor of PHP coroutine (code). For more information, please follow other related articles on the PHP Chinese website!