匿名函数

// 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关键字。

//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. 减少循环

// 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。
// 其中有一个方法用来计算购物车中所有商品的总价格。该方法使用了一个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. 减少函数的参数

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. 解除递归函数

// ↓↓ 注意,这里的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. 关于延迟绑定

$result = 0;
$one = function(){
var_dump($result);
};
$two = function() use ($result){
var_dump($result);
}; // 如果使用引用,就能使use里面的变量完成延迟绑定,也就是在调用的时候再赋值;
$three = function() use (&$result){
var_dump($result);
}; $four = function() use ($result){
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(1)

几个配合回调或闭包的函数

bool array_walk ( array &$array , callable $funcname [, mixed $userdata = NULL ] )

/**
* @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 ]

$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 ]] )

$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 ] )

/**
* @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 ] )


/**
* 用回调函数迭代地将数组简化为单一的结果值,解释不清楚的一看代码就明白了;
* @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 ]] )

/**
* @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 )

/**
* @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的匿名函数和闭包的更多相关文章

  1. JavaScript笔记 第十六章 匿名函数和闭包

    1.匿名函数 2.闭包 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数. 一.匿名函数 //普通函数 function getName() { return 'name'; } a ...

  2. 第一百一十节,JavaScript匿名函数和闭包

    JavaScript匿名函数和闭包 学习要点: 1.匿名函数 2.闭包 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.声明:本节内容需要有面向对象和少量设计模式基础,否则无法听懂 ...

  3. JavaScript(第十五天)【匿名函数和闭包】

      学习要点: 1.匿名函数 2.闭包 匿名函数就是没有名字的函数,闭包是可访问一个函数作用域里变量的函数.声明:本节内容需要有面向对象和少量设计模式基础,否则无法听懂.(所需基础15章的时候已经声明 ...

  4. 从匿名函数(闭包特性)到 PHP 设计模式之容器模式

    匿名函数(匿名函数) 匿名函数,也叫闭包函数,它允许临时创建一个没有指定名称的函数,常用作回调函数参数的值,也可以作为变量的值来使用.具体的使用见以下示例代码: /* 示例一:声明一个简单匿名函数,并 ...

  5. php的匿名函数和闭包函数

    php的匿名函数和闭包函数 tags: 匿名函数 闭包函数 php闭包函数 php匿名函数 function use 引言:匿名函数和闭包函数都不是特别高深的知识,但是很多刚入门的朋友却总是很困惑,因 ...

  6. js匿名函数和闭包总结

    js匿名函数和闭包总结 一.总结 一句话总结:匿名函数的最主要作用是创建闭包,闭包就是将函数内部和函数外部连接起来的一座桥梁.内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕.闭包可以用 ...

  7. 匿名函数、闭包、lambda表达式、Block

    C#有lambda.匿名函数,js有匿名函数.闭包,OC中有block,看到这是不是心中有一万个草泥马在跑,不过它们这些都是换汤不换药,不同语言名字不一样. 从功能性上说lambda和closure( ...

  8. Golang之匿名函数和闭包

    Go语言支持匿名函数,即函数可以像普通变量一样被传递或使用. 使用方法如下: main.go package main import ( "fmt" ) func main() { ...

  9. js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)

    js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...

  10. javascript进阶课程--第三章--匿名函数和闭包

    javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...

随机推荐

  1. sql server 索引阐述系列三 表的堆组织

    一.   概述 这一节来详细介绍堆组织,通过讲解堆的结构,堆与非聚集索引的关系,堆的应用场景,堆与聚集索引的存储空间占用,堆的页拆分现象,最后堆的使用建议 ,这几个维度来描述堆组织.在sqlserve ...

  2. MySQL导入导出实践

    最近一次数据迁移,需要将MySQL的数据导出.处理后导入到新表和ES.这里做个简单记录,方便后续查询. 注: 为了写文章方便及隐私安全,实际内容会有所简化.例如表结构简化.数据库连接部分全部用 xxx ...

  3. python中执行该文件,就调用 mian 方法

    代码: test.py import student def main(): st = student.student(1001, 'tommy', 18) st.sing() st.dance() ...

  4. php-fpm无法使用系统环境变量的解决方法

    为了防止任意环境变量到达php-fpm进程,默认默认php-fpm是会清空系统环境变量的, 解决办法 修改php-fpm配置的clear_env = no (默认是yes)

  5. Socket网络编程基本介绍

    一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...

  6. Python下用Scrapy和MongoDB构建爬虫系统(1)

    本文由 伯乐在线 - 木羊 翻译,xianhu 校稿.未经许可,禁止转载!英文出处:realpython.com.欢迎加入翻译小组. 这篇文章将根据真实的兼职需求编写一个爬虫,用户想要一个Python ...

  7. spring学习(三) ———— spring事务操作

    前面一篇博文讲解了什么是AOP.学会了写AOP的实现,但是并没有实际运用起来,这一篇博文就算是对AOP技术应用的进阶把,重点是事务的处理. --wh 一.jdbcTemplate 什么是JdbcTem ...

  8. vsphere 虚拟机的迁移,冷迁移,vmotion(热迁移)

    备注:(理论部分参考王春海老师的课程) 一.概述 1.vsphere数据中心当处于某种目的进行维护时,需要将某台主机上运行或关闭的虚拟机,迁移到其他主机上,这个时候就需要使用迁移 2.可以使用冷迁移或 ...

  9. springBoot系列-->springBoot注解大全

    一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfiguration ...

  10. Java学习笔记之——封装

    1. 属性和方法放到类中 2. 信息的隐藏 (1) 属性的隐藏 (2) 方法实现的细节隐藏 3. 权限修饰符: 从小到大的顺序:private->默认的(什么都不写)->protected ...