接觸PHP一段時間以來,我一直以為這是一種基於函數式編程的語言是沒有閉包這種東西的,但事實上卻顛覆了我的想法,PHP竟然有閉包,下面我們一起來接觸一下PHP的所謂的閉包。
根據PHP官網的定義來看,閉包(closure)又可以叫做匿名函數(Anonymous function),其實我們知道在JS中,閉包和匿名函數有着一定的區別,但是在PHP中卻等同了,那么這肯定有一些區別的,那么我們和JS當中的閉包對比的來看看。
1、語句結構
在JS中,閉包和普通的函數定義沒有什么區別,但是在PHP中,由於存在函數內部不能訪問全局作用的,所以就需要一種可以引入上一級作用域的語法結構,這種就是
function () use () {}
將需要引入到這個函數作用於內的變量寫入到use的括號里面就可以了,舉個例子
<?php $a = 1; $closure = function () use ($a) { echo $a; }; $closure();
?>
輸出的結果為
1
這次就實現了閉包的功能了,可以和上級作用域產生了聯系了
2、變量執行的時候是運行時賦值還是函數聲明的時候賦的值?
學過JS的到這里一定認為這個$a變量當變化的時候,根據JS引用的理論,函數執行的結果也是變化的,但事實究竟是這樣么?看例子:
<?php $a = 1; $closure = function () use ($a) { echo $a; }; $closure(); $a=2; $closure(); ?>
大家猜猜結果會是什么?
1 1
哎??為什么不是 1 2 呢?
因為對於PHP來說的閉包當聲明閉包的時候,就已經將值重新開辟了一塊內存賦值給了use中的$a所以,不過外部的$a怎么變,閉包執行的結果是不變的,那么我們怎么能讓他變化呢?
先給大家一個提示,PHP實現閉包的本質其實是將這個特殊的函數轉換成了一個類。
說到這里,大家是不是有一點明白了呢?既然是類,那么我們可以使用引用來傳遞use當中的值。
讓我們再試一下
<?php $a = 1; $closure = function () use (&$a) {//注意這里,加了一個& echo $a; }; $closure(); $a=2; $closure(); ?>
再運行一下看看
1 2
這次結果對了吧。
不僅如此,引用之后,如果在閉包當中修改引入的變量值,原本的變量的值也會修改的,但是不過不加&,那么在閉包中修改變量的值得時候,即使這次修改有效了,下次重新運行閉包函數后又會回到之前的值,相當於沒有修改。舉個例子:
不加&:
<?php $a = 1; $closure = function () use ($a) { $a++; echo $a,' '; }; $closure(); $closure(); $a=-5; $closure(); $closure(); ?>
輸出為:
2 2 2 2
加了&之后
輸出為
2 3 -4 -3
總結:
對應PHP中的閉包,和JS中的閉包還是有本質的區別的,JS的閉包是語言原生支持的,所以感覺比較符合人的思考方式,而PHP得閉包就是將閉包的這種特性抽象成了類的方式,然后以類的形式進行處理,畢竟是抽象出來的,還不是很符合人們的思考方式。
在接觸了PHP的閉包之后,我深深的覺得PHP真是雜啊………………
PS:
1、不要忘記了在閉包的賦值語句最后面的分號,畢竟這是一個語句,還要是有分號的。
2、對於函數的傳入參數等東西,和普通的參數寫法是一樣的。
3、要注意函數調用的時候不要忘記了$,因為閉包函數的本質還是一個變量的,不過是一個可以執行的變量了而已。如果去掉$,PHP解釋器將會認為這是一個函數而不是一個閉包函數從而出錯。
4、除了上面的那幾點和JS的不同以外,其他的都是可以的,比如可以作為函數的返回值等等的內容。
