最近學(xué)習(xí)PHP,看到了一段代碼,其中涉及到了匿名函數(shù)以及array_reduce,把代碼敲出來用各種方法分析也沒想出是怎么調(diào)用的,代碼如下:
<?php
interface Middleware
{
public static function handle(Closure $next);
}
class VerifyCsrfToken implements Middleware
{
public static function handle(Closure $next)
{
echo "(5)驗(yàn)證Csrf-Token".'<br>';
$next();
}
}
class ShareErrorsFromSession implements Middleware
{
public static function handle(Closure $next)
{
echo "(4)如果session中有'errors'變量,則共享它".'<br>';
$next();
}
}
class StartSession implements Middleware
{
public static function handle(Closure $next)
{
echo "(3)開啟session,獲取數(shù)據(jù)".'<br>';
$next();
echo "(7)保存數(shù)據(jù),關(guān)閉session".'<br>';
}
}
class AddQueuedCookiesToResponse implements Middleware
{
public static function handle(Closure $next)
{
$next();
echo "(8)添加下一次請求需要的cookie".'<br>';
}
}
class EncryptCookies implements Middleware
{
public static function handle(Closure $next)
{
echo "(2)對輸入請求的cookie進(jìn)行解密".'<br>';
$next();
echo "(9)對輸出相應(yīng)的cookie進(jìn)行加密".'<br>';
}
}
class CheckForMaintenanceMode implements Middleware
{
public static function handle(Closure $next)
{
echo "(1)確定當(dāng)前程序是否處于維護(hù)狀態(tài)".'<br>';
$next();
}
}
function getSlice()
{
return function($stack, $pipe)
{
return function() use ($stack, $pipe)
{
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = [
"CheckForMaintenanceMode",
"EncryptCookies",
"AddQueuedCookiesToResponse",
"StartSession",
"ShareErrorsFromSession",
"VerifyCsrfToken"
];
$firstSlice = function() {
echo "(6)請求向路由器傳遞,返回響應(yīng).".'<br>';
};
$pipes = array_reverse($pipes);
$go = array_reduce($pipes, getSlice(),$firstSlice);
$go();
}
then();
?>
還望有大神能幫忙詳解下$go = array_reduce($pipes, getSlice(),$firstSlice);和$go();這兩段代碼背后的每一步的調(diào)用執(zhí)行流程,以及調(diào)用時的參數(shù)傳遞是哪些,如果能用流程圖表示就更好啦,謝謝。
那么久了還沒人回答.我來回答一下吧.
首先是這樣的.我們看下面的代碼來理解一下
<?php
function myfunction($v1,$v2)
{
return $v1+$v2;
}
$a=array(10,15,20);
print_r(array_reduce($a,"myfunction",5)); //50
?>
上面的結(jié)果為50.那么它的過程是怎么樣的呢?我們對代碼進(jìn)行改良
function myfunction($v1, $v2)
{
var_dump($v1, $v2);
return $v1 + $v2;
}
$a = array(10, 15, 20);
print_r(array_reduce($a, "myfunction", 5)); //50
echo "\n";
然后可以看到如下輸出
int(5)
int(10)
int(15)
int(15)
int(30)
int(20)
50
第一個v1 = 5,v2 = 10;
第二個v1 = 15 (前一個返回的值) , v2 = 15; $a[1]的值;
第三個v1 = 30 (上一次的返回值) , v2 = 20; $a[2]的值;
最后輸出50. 那么我們看第一個值為什么是5? 因?yàn)閍rray_reduce接收的第3個參數(shù)就是表示當(dāng)?shù)谝淮蔚臅r候傳遞的值。下面我們來自己實(shí)現(xiàn)一個array_reduce去深度的理解它 :)
function myfunction($v1, $v2)
{
var_dump($v1, $v2);
return $v1 + $v2;
}
$a = array(10, 15, 20);
print_r(my_array_reduce($a, "myfunction", 5)); //50
echo "\n";
/**
* array_reduce
* @param array $arr
* @param callable $fn
* @param null $initial
* @return mixed
*/
function my_array_reduce(array $arr, callable $fn, $initial = null)
{
$v = $initial;
foreach ($arr as $item) {
$v = $fn($v, $item);
}
return $v;
}
這樣是不是好多了呢?
下面是根據(jù)題主的問題進(jìn)行補(bǔ)充
$arr = [
'VerifyCsrfToken'
];
function getSlice()
{
return function($stack, $pipe)
{
return function() use ($stack, $pipe)
{
return $pipe::handle($stack);
};
};
}
$firstSlice = function() {
echo "(6)請求向路由器傳遞,返回響應(yīng).".'<br>';
};
$go = array_reduce($pipes, getSlice(),$firstSlice);
$go();
當(dāng)arr 是上面的數(shù)組 以及回調(diào)的方法是上面的方法時.我們來看看發(fā)生了什么
首先
1.getSlice的返回值是function
當(dāng)arr第一次循環(huán)的時候,根據(jù)我們上面所提到的array_reduce的原理看看發(fā)生了什么?
$arr = [
'VerifyCsrfToken'
];
function getSlice()
{
return function($stack, $pipe)
{
return function() use ($stack, $pipe)
{
return $pipe::handle($stack);
};
};
}
首先看這里
$go = array_reduce($pipes, getSlice(),$firstSlice);
第二個參數(shù)傳的并不是callback 而是 直接寫的 getSlice(); 那么這個函數(shù)將會直接執(zhí)行并且將返回值傳遞給 array_reduce的第二個參數(shù).
也就是直接返回
function ($stack, $pipe) {
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
};
也就是和下面的寫法是等價的。
function getSlice($stack, $pipe)
{
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
}
$firstSlice = function () {
echo "(6)請求向路由器傳遞,返回響應(yīng)\n";
};
$go = my_array_reduce($pipes, "getSlice", $firstSlice);
$go();
只是因?yàn)榍罢叩膶懛ǜ觾?yōu)雅 易于讓ide查找;
弄清楚了這個我們接下來繼續(xù)看。
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
當(dāng)?shù)谝淮蔚臅r候 $stack 的值為$firstSlice
pipe 的值 為 VerifyCsrfToken.
那么這個函數(shù)被執(zhí)行了.$firstSlice當(dāng)作參數(shù)。
所以當(dāng)調(diào)用$go();時
所有的pipe::handle方法會立即執(zhí)行。
而每次都把$stack作為參數(shù)
所以執(zhí)行順序是倒過來了。因?yàn)榈阶詈笠淮蔚臅r候 $next 才 === $firstSlice
$pipes = [
"VerifyCsrfToken",
"VerifyCsrfToken1"
];
/**
* array_reduce
* @param array $arr
* @param callable $fn
* @param null $initial
* @return mixed
*/
function my_array_reduce($arr, callable $fn, $initial = null)
{
$v = $initial;
foreach ($arr as $item) {
$v = $fn($v, $item);
}
return $v;
}
再來回顧這段代碼.為什么VerifyCsrfToken1先執(zhí)行呢?
因?yàn)楫?dāng)foreach執(zhí)行完畢的時候. $item = $pipes[count($pipes)-1];
也就是最后一個而 $v 永遠(yuǎn)為上一個return 的 值。
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
北大青鳥中博軟件學(xué)院創(chuàng)立于2003年,作為華東區(qū)著名互聯(lián)網(wǎng)學(xué)院和江蘇省首批服務(wù)外包人才培訓(xùn)基地,中博成功培育了近30000名軟件工程師走向高薪崗位,合作企業(yè)超4
中公教育集團(tuán)創(chuàng)建于1999年,經(jīng)過二十年潛心發(fā)展,已由一家北大畢業(yè)生自主創(chuàng)業(yè)的信息技術(shù)與教育服務(wù)機(jī)構(gòu),發(fā)展為教育服務(wù)業(yè)的綜合性企業(yè)集團(tuán),成為集合面授教學(xué)培訓(xùn)、網(wǎng)
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機(jī)構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗(yàn),技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點(diǎn)難點(diǎn)突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗(yàn)。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。