(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP 8)
array_reduce — 用回调函数迭代地将数组简化为单一的值
说明 ¶
array_reduce(array $array, callable $callback, mixed $initial = null): mixed
array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值。
参数 ¶
array
输入的 array。
callback
callback(mixed $carry, mixed $item): mixed
carry
携带上次迭代的返回值; 如果本次迭代是第一次,那么这个值是 initial。
item
携带了本次迭代的值。
initial
如果指定了可选参数 initial,该参数将用作处理开始时的初始值,如果数组为空,则会作为最终结果返回。
返回值 ¶
返回结果值。
如果数组为空,并且没有指定 initial 参数,array_reduce() 返回 null。
<?php
interface Middleware
{
public static function handle(Closure $next);
}
class AddQueuedCookiesToResponse implements Middleware
{
public static function handle(Closure $next)
{
echo "add before\n";
$next();
echo "add after\n";
}
}
class EncryptCookies implements Middleware
{
public static function handle(Closure $next)
{
echo "encryp before\n";
$next();
echo "encryp after\n";
}
}
class CheckForMaintenanceMode implements Middleware
{
public static function handle(Closure $next)
{
echo "check before\n";
$next();
echo "check after\n";
}
}
function getSlice() // 返回一个函数,与上文的f一致
{
return function ($stack, $pipe) {
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = [
"CheckForMaintenanceMode",
"EncryptCookies",
"AddQueuedCookiesToResponse",
];
$firstSlice = function () { // 上文的目标函数 target
echo "请求向路由器传递,返回响应.\n";
};
$pipes = array_reverse($pipes);
$closure = array_reduce($pipes, getSlice(), $firstSlice);
var_dump($closure);//打印下该闭包
// 因为最终返回了一个函数,所以需要call_user_func
call_user_func(array_reduce($pipes, getSlice(), $firstSlice));
}
then();
echo "\n";
//array_reduce($pipes, getSlice(), $firstSlice),执行完成后相当于生成了f嵌套闭包
function f()
{
return CheckForMaintenanceMode::handle(
function () {
return EncryptCookies::handle(
function () {
return AddQueuedCookiesToResponse::handle(function () {
echo "请求向路由器传递,返回响应.\n";
});
}
);
}
);
}
call_user_func('f');
嵌套闭包的解包方式和递归的方式类似,它是先从外到内,然后从内回归到外面,所以输出结果是这样的,以上程序执行结果为:
object(Closure)#5 (1) {
["static"]=>
array(2) {
["stack"]=>
object(Closure)#4 (1) {
["static"]=>
array(2) {
["stack"]=>
object(Closure)#3 (1) {
["static"]=>
array(2) {
["stack"]=>
object(Closure)#1 (0) {
}
["pipe"]=>
string(26) "AddQueuedCookiesToResponse"
}
}
["pipe"]=>
string(14) "EncryptCookies"
}
}
["pipe"]=>
string(23) "CheckForMaintenanceMode"
}
}
check before
encryp before
add before
请求向路由器传递,返回响应.
add after
encryp after
check after
check before
encryp before
add before
请求向路由器传递,返回响应.
add after
encryp after
check after
当第一次迭代的时候 $stack 的值为$firstSlice,$pipe 的值为’AddQueuedCookiesToResponse’。第二次迭代时,会把第一次迭代生成的
function () {
return AddQueuedCookiesToResponse::handle(function () {
echo "请求向路由器传递,返回响应.\n";
});
}
做为$stack传入,$pipe的值为’EncryptCookies’,
function () {
return EncryptCookies::handle(
function () {
return AddQueuedCookiesToResponse::handle(function () {
echo "请求向路由器传递,返回响应.\n";
});
}
);
}
以此类推,生成嵌套的闭包函数,当调用call_user_func时,会依此执行pipe::handle方法,每次会把handle里的闭包传入(即每次都把var_dump($closure),打印结果里stack下的闭包作为参数),在hanle方法里$next()会调用传入的闭包,直到最后一次$next才===$firstSlice。
array_reduce($pipes, getSlice(), $firstSlice),执行完成后生成了f嵌套闭包,从执行后的打印结果看出来,两者执行结果一致。
带参数的示例:
<?php
interface Middleware
{
public static function handle($message,Closure $next);
}
class AddQueuedCookiesToResponse implements Middleware
{
public static function handle($message,Closure $next)
{
echo "add before".$message."\n";
$message = '-add';
return $next($message);
echo "add after\n";
}
}
class EncryptCookies implements Middleware
{
public static function handle($message,Closure $next)
{
echo "encryp before".$message."\n";
$message = '-encry';
//return ['code'=>1];
return $next($message);
echo "encryp after\n";
}
}
class CheckForMaintenanceMode implements Middleware
{
public static function handle($message,Closure $next)
{
echo "check before".$message."\n";
$message = '-check';
return $next($message);
echo "check after\n";
}
}
function getSlice() // 返回一个函数,与上文的f一致
{
return function ($stack, $pipe) {
return function ($message) use ($stack, $pipe) {
return $pipe::handle($message,$stack);
};
};
}
function then()
{
$pipes = [
"CheckForMaintenanceMode",
"EncryptCookies",
"AddQueuedCookiesToResponse",
];
$firstSlice = function () { // 上文的目标函数 target
echo "请求向路由器传递,返回响应.\n";
return [];
};
$pipes = array_reverse($pipes);
$closure = array_reduce($pipes, getSlice(), $firstSlice);
// 因为最终返回了一个函数,所以需要call_user_func
$ret = call_user_func(array_reduce($pipes, getSlice(), $firstSlice),'abc');
var_dump($ret);
}
then();
echo "\n";
//array_reduce($pipes, getSlice(), $firstSlice),执行完成后相当于生成了f嵌套闭包
function f($p)
{
return CheckForMaintenanceMode::handle($p,
function ($p) {
return EncryptCookies::handle($p,
function ($p) {
return AddQueuedCookiesToResponse::handle($p,function () {
echo "请求向路由器传递,返回响应.\n";
return [];
});
}
);
}
);
}
$ret = call_user_func('f','cba');
var_dump($ret);
打印结果
check beforeabc
encryp before-check
add before-encry
请求向路由器传递,返回响应.
array(0) {
}
check beforecba
encryp before-check
add before-encry
请求向路由器传递,返回响应.
array(0) {
}
闭包直接使用$next()调用,生成嵌套闭包示例:
<?php
$next = function(){
return 'next function initial';
};
$itemHandler[] = function($message,Closure $next){
//自定义1
var_dump("自定义1");
return $next($message);
};
$itemHandler[] = function($message,Closure $next){
//自定义2
var_dump("自定义2");
return $next($message);
};
foreach(array_reverse($itemHandler) as $item){
$next = function($p) use($item,$next){
return $item($p,$next);
};
};
var_dump($next(123));
var_dump($next);
打印结果:
string(10) "自定义1"
string(10) "自定义2"
string(21) "next function initial"
object(Closure)#5 (2) {
["static"]=>
array(2) {
["item"]=>
object(Closure)#2 (1) {
["parameter"]=>
array(2) {
["$message"]=>
string(10) "<required>"
["$next"]=>
string(10) "<required>"
}
}
["next"]=>
object(Closure)#4 (2) {
["static"]=>
array(2) {
["item"]=>
object(Closure)#3 (1) {
["parameter"]=>
array(2) {
["$message"]=>
string(10) "<required>"
["$next"]=>
string(10) "<required>"
}
}
["next"]=>
object(Closure)#1 (0) {
}
}
["parameter"]=>
array(1) {
["$p"]=>
string(10) "<required>"
}
}
}
["parameter"]=>
array(1) {
["$p"]=>
string(10) "<required>"
}
}