## 匿名函數
```php
// Example1
$func = function( $param ) {
echo $param;
};
$func( 'some string' );//輸出:some string
// Example2
function callFunc( $func ) {
$func( 'some string' );
}
$printStrFunc = function( $str ) {
echo $str;
};
callFunc( $printStrFunc );
//可以直接將匿名函數進行傳遞。如果你了解js,這種寫法可能會很熟悉
callFunc( function( $str ) {
echo $str;
} );
```
## 閉包
PHP在默認情況下,匿名函數內不能調用所在代碼塊的上下文變量,而需要通過使用use關鍵字。
```php
//1. 通過閉包獲取當前函數環境外的變量值副本。
function getMoney() {
$rmb = 1;
$dollar = 6;
$func = function() use ( $rmb ) {
echo $rmb; //1
echo $dollar; //報錯,找不到dorllar變量
};
$func();
}
getMoney();
//2. 之所以稱為副本,是因為通過閉包傳值到匿名函數內的變量,值也是不能改變。
function getMoney() {
$rmb = 1;
$func = function() use ( $rmb ) {
$rmb += 2;
echo $rmb; // 3
};
$func();
echo $rmb; // 還是1沒有改變;
}
getMoney();
//3. 如果要改變外部變量的值,還是得通過傳址的方法
function getMoney() {
$rmb = 1;
$func = function() use ( &$rmb ) {
$rmb += 2;
echo $rmb; // 3
};
$func();
echo $rmb; // 3;
}
getMoney();
//4.
function getMoneyFunc() {
$rmb = 1;
$func = function() use(&$rmb){
echo $rmb;
//把$rmb的值加1
$rmb++;
};
return $func; // 如果將匿名函數返回給外界,匿名函數會保存use所引用的變量,而外界則不能得到這些變量,這樣形成‘閉包’
}
$getMoney = getMoneyFunc();
$getMoney(); // 1
$getMoney(); // 2
$getMoney(); // 3
```
### 閉包的好處
**1. 減少循環**
```php
// 一個基本的購物車,包括一些已經添加的商品和每種商品的數量。
// 其中有一個方法用來計算購物車中所有商品的總價格。該方法使用了一個closure作為回調函數。
class Cart{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product , $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] : false;
}
public function getTotal($tax)
{
$total = 0.00;
// 使用閉包減少循環;
$callback = function($quantity , $product) use ($tax , &$total){
$pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products , $callback);
return round($total , 2);;
}
}
$my_cart = new Cart;
// 往購物車里添加條目
$my_cart->add('butter' , 1);
$my_cart->add('milk' , 3);
$my_cart->add('eggs' , 6);
// 打出出總價格,其中有 5% 的銷售稅.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
```
**2. 減少函數的參數**
```php
function html($code , $id = "" , $class = "")
{
if ($id !== "")
$id = " id = \"{$id}\"";
$class = ($class !== "") ? " class =\"$class\"" : "";
$open = "<$code$id$class>";
$close = "</$code>";
return function($inner = "") use ($open , $close){
return "$open$inner$close";
};
}
$tag = html('div','','class');
// 可讀性和可維護性大大提高;
echo $tag('div1,div1,div1');
echo PHP_EOL;
echo $tag('div2,div2,div2');
```
**3. 解除遞歸函數**
```php
// ↓↓ 注意,這里的fib一定要用引用哦,因為第一次的時候就會Notice: Undefined variable,然后后面的fib()就會錯誤;
$fib = function($n) use (&$fib){
if ($n == 0 || $n == 1)
return 1;
return $fib($n - 1) + $fib($n - 2);
};
echo $fib(2) . "\n"; // 2
$lie = $fib;
$fib = function(){
die('error');
};//rewrite $fib variable
echo $lie(5); // error 達到遞歸解除;
```
**4. 關于延遲綁定**
```php
$result = 0;
$one = function(){
var_dump($result);
};
$two = function() use ($result){
var_dump($result);
};
// 在回調生成的時候進行賦值;
$four = function() use ($result){
//0 回調生成的時候賦值,也就是$result = 0;
var_dump($result);
};
// 如果使用引用,就能使use里面的變量完成延遲綁定,也就是在調用的時候再賦值;
$three = function() use (&$result){
//1 在調用的時候再賦值進去,也就是1,注意對象類型也屬于引用;
var_dump($result);
};
$result += 1;
$one(); // outputs NULL: $result is not in scope
$two(); // outputs int(0): $result was copied
$three(); // outputs int(1)
$four(); // outputs int(0)
```
## 幾個配合回調或閉包的函數
`bool array_walk ( array &$array , callable $funcname [, mixed $userdata = NULL ] )`
```php
/**
* @param array $array
* @param callable $funcname ()
* @param mixed|NULL $userdata
* @return bool
* bool array_walk ( array &$array , callable $funcname [, mixed $userdata = NULL ] )
*/
$fruits = array(
"d" => "lemon" ,
"a" => "orange" ,
"b" => "banana" ,
"c" => "apple"
);
$test_print = function(&$item2 , $key, $prefix){
$item2 .= ' 10';
echo "{$prefix} : $key => $item2\n";
};
/*
this result : d => lemon
this result : a => orange
this result : b => banana
this result : c => apple
*/
array_walk($fruits , $test_print, 'this result');
print_r($fruits);
/*
Array
(
[d] => lemon 10
[a] => orange 10
[b] => banana 10
[c] => apple 10
)
*/
```
---
`bool array_walk_recursive ( array &$input , callable $funcname [, mixed $userdata = NULL ]`
```php
$sweet = array(
'a' => 'apple' ,
'b' => 'banana'
);
$fruits = array(
'sweet' => $sweet ,
'sour' => 'lemon'
);
$test_print = function($item , $key)
{
echo "$key holds $item\n";
};
array_walk_recursive($fruits , $test_print);
/*
* 自動跳過sweet,因為sweet是數組;任何其值為 array 的鍵都不會被傳遞到回調函數中去
a holds apple
b holds banana
sour holds lemon
*/
```
---
`array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )`
```php
$odd = function($var){
return ($var & 1);
};
$even = function($var){
return (!($var & 1));
};
$array1 = array( "a" => 1 , "b" => 2 , "c" => 3 , "d" => 4 , "e" => 5 );
$array2 = array( 6 , 7 , 8 , 9 , 10 , 11 , 12 );
echo "Odd :\n";
print_r(array_filter($array1 , "odd"));
/*
Odd :
Array
(
[a] => 1
[c] => 3
[e] => 5
)
*/
echo "Even:\n";
print_r(array_filter($array2 , "even"));
/*
Even:
Array
(
[0] => 6
[2] => 8
[4] => 10
[6] => 12
)
*/
# 如果不傳第二參數的的話
$entry = array(
0 => 'foo',
1 => false,
2 => -1,
3 => null,
4 => ''
);
print_r(array_filter($entry));
/*
* 當前值為false的話就filter;
Array
(
[0] => foo
[2] => -1
)
*/
```
---
`array array_map ( callable $callback , array $arr1 [, array $array ] )`
```php
/**
* @param callable $callback
* @param array $arr1
* @param array $array
*/
$func = function($value) {
return $value * 2;
};
print_r(array_map($func, range(1, 5)));
/*
Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 8
[4] => 10
)
*/
$show_Spanish = function($n , $m){
return ("The number $n is called $m in Spanish");
};
$a = array( 1 , 2 , 3 , 4 , 5 );
$b = array( "uno" , "dos" , "tres" , "cuatro" , "cinco" );
$c = array_map($show_Spanish , $a , $b);
/**
print_r($c);
Array
(
[0] => The number 1 is called uno in Spanish
[1] => The number 2 is called dos in Spanish
[2] => The number 3 is called tres in Spanish
[3] => The number 4 is called cuatro in Spanish
[4] => The number 5 is called cinco in Spanish
)
*/
$map_Spanish = function($n , $m){
return (array($n => $m));
};
$d = array_map($map_Spanish , $a , $b);
print_r($d);
/**
Array (
[0] => Array ( [1] => uno )
[1] => Array ( [2] => dos )
[2] => Array ( [3] => tres )
[3] => Array ( [4] => cuatro )
[4] => Array ( [5] => cinco )
)
*/
```
---
`mixed array_reduce ( array $input , callable $function [, mixed $initial = NULL ] )`
```php
/**
* 用回調函數迭代地將數組簡化為單一的結果值,解釋不清楚的一看代碼就明白了;
* @param array $input
* @param callable $function
* @param mixed|NULL $initial 如果指定了可選參數 initial,該參數將被當成是數組中的第一個值來處理,或者如果數組為空的話就作為最終返回值。
*/
$rsum = function($result , $value){
// $result 初始值為NULL, 如果有第三參數的話,第三參數為初始值;
$result += $value;
return $result;
};
$rmul = function($result , $value){
$result *= $value;
return $result;
};
$a = array(1, 2, 3, 4, 5);
$x = array();
$b = array_reduce($a, $rsum); // (NULL)0+1+2+3+4+5 = 15;
$c = array_reduce($a, $rmul, 10); // 10*1*2*3*4*5 = 1200;
$d = array_reduce($x, $rsum, "No data to reduce"); // No data to reduce
```
---
`mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )`
```php
/**
* @param mixed $pattern 正則模式;
* @param callable $callback
* @param mixed $subject
* @param int $limit 對于每個模式用于每個 subject 字符串的最大可替換次數。 默認是-1(無限制)。
* @param int $count 如果指定,這個變量將被填充為替換執行的次數。
* mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )
*/
// 將文本中的年份增加一年.
$text = "April fools day is 04/01/2002\n";
$text .= "Last christmas was 12/24/2001\n";
// 回調函數
$next_year = function($matches){
// 通常: $matches[0]是完成的匹配
// $matches[1]是第一個捕獲子組的匹配
// 以此類推
return $matches[1] . ($matches[2] + 1);
};
echo preg_replace_callback("|(\d{2}/\d{2}/)(\d{4})|" , $next_year , $text);
```
---
`mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )`
`mixed call_user_func_array ( callable $callback , array $param_arr )`
```php
/**
* @param callable $callback 第一個參數為需要調用的函數; 如果是數組array($classname, $methodname)
* @param mixed $parameter 第二個參數開始就是隊列進該函數的參數;
* @param mixed $parameter2
* @param mixed $parameter3
* ..
* @return 返回值:返回調用函數的結果,或FALSE
*/
$eat = function($fruit , $num){ //參數可以為多個
echo "You want to eat $fruit $num pcs, no problem\n";
};
call_user_func($eat , "apple" , 10); //print: You want to eat apple 10 pcs, no problem;
call_user_func($eat , "orange" , 5); //print: You want to eat orange 5 pcs,no problem;
// 調用類方法
class myclass {
public static function say_hello($name,$message)
{
echo "Hello! $name $message";
}
}
//array(類名,靜態方法名),參數
call_user_func(array('myclass', 'say_hello'), 'dain_sun', 'good person');
call_user_func_array(array('myclass', 'say_hello'), array('dain_sun', 'good person'));
// Hello! dain_sun good person
```
- 現代化PHP特性
- php7常用特性整理
- 反射機制Reflection
- 依賴注入與服務容器
- 抽象類與接口
- 類多繼承的替代方案Traits
- 類的延遲綁定(后期綁定)
- 生成器語法
- 匿名函數和閉包
- 匿名類
- 理解php的output buffer
- 斷言ASSERT
- 魔術方法小結
- Zend Opcache字節碼緩存
- 內置的http服務器
- SPL標準庫
- 【SPL標準庫專題(1)】SPL簡介
- 【SPL標準庫專題(2)】Iterator
- 【SPL標準庫專題(3)】Classes
- 【SPL標準庫專題(4)】Exceptions
- 【SPL標準庫專題(5)】Datastructures:SplDoublyLinkedList
- 【SPL標準庫專題(6)】Datastructures:SplStack & SplQueue
- 【SPL標準庫專題(7)】Datastructures:SplPriorityQueue
- 【SPL標準庫專題(8)】Datastructures:SplHeap & SplMaxHeap & SplMinHeap
- 【SPL標準庫專題(9)】Datastructures:SplFixedArray
- 【SPL標準庫專題(10)】Datastructures:SplObjectStorage
- PHPcomposer使用手札[ing]
- PHP中的多態
- 通過命名空間實現自動加載的框架雛形
- 日期與金額
- PHPstorm使用攻略
- 筆記本