匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数参数的值。当然,也有其它应用的情况。
php的闭包不会像js那样自动封装应用的状态,而是需要手动bindTo() 或者 use,把你需要的变量或值存到闭包里面。
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
?>
$luckyDip = array(
function() {
echo "You got a bag of toffees!";
},
function() {
echo "You got a toy car!";
},
function() {
echo "You got some balloons!";
}
);
$choice = rand( 0, 2 );
$luckyDip[$choice]();
比如,在工作中经常有一个场景:改变数组中每一个元素的内容,这时可以用array_map + 匿名函数的方式解决。
$names = array( "fred", "mary", "sally" );
print_r ( array_map( function( $name ) {
return "Hello " . ucfirst( $name ) . "!";
}, $names ) );
usort: 匿名函数返回-1表示,把b往后拿。返回1表示,把b往前拿。
$people = array(
array( "name" => "Fred", "age" => 39 ),
array( "name" => "Sally", "age" => 23 ),
array( "name" => "Mary", "age" => 46 )
);
usort( $people, function( $personA, $personB ) {
return ( $personA["age"] < $personB["age"] ) ? -1 : 1;
} );
print_r( $people );
匿名函数的另一个常见用途是创建闭包。闭包是一个函数,它保留对其封闭范围内变量的访问权限。
function getGreetingFunction() {
$timeOfDay = "morning";
return ( function( $name ) use ( &$timeOfDay ) {
$timeOfDay = ucfirst( $timeOfDay );
return ( "Good $timeOfDay, $name!" );
} );
};
$greetingFunction = getGreetingFunction();
echo $greetingFunction( "Fred" );
$people = array(
array( "name" => "Fred", "age" => 39 ),
array( "name" => "Sally", "age" => 23 ),
array( "name" => "Mary", "age" => 46 )
);
function getSortFunction( $sortKey ) {
return function( $personA, $personB ) use ( $sortKey ) {
return ( $personA[$sortKey] < $personB[$sortKey] ) ? -1 : 1;
};
}
echo "Sorted by name:<br><br>";
usort( $people, getSortFunction( "name" ) );
print_r( $people );
echo "<br>";
echo "Sorted by age:<br><br>";
usort( $people, getSortFunction( "age" ) );
print_r( $people );
echo "<br>";
其实闭包给我的感觉就像是,把变量或者值,预先存放到函数里面。也就是说这个函数是动态创建的,在执行时就能体现出多态性。
通过闭包的bindTo方法,可以把对象内部的$this绑定到其他对象上(App对象),第二个参数也很重要,指定了绑定闭包的那个对象所属的类,因此闭包可以访问到 APP对象的私有属性
<?php
class App {
private $name;
protected $routes;
public function addRoute($path, $callback) {
$this->routes[$path] = $callback->bindTo($this, __CLASS__);
}
public function dispatch($path) {
if (isset($this->routes[$path])) {
$callback = $this->routes[$path];
$callback();
}
}
public function getName() {
return $this->name;
}
}
$app = new App();
$app->addRoute('index', function (){
$this->name = 'index';
});
$app->dispatch('index');
echo $app->getName();