在PHP 5.3.0中,“use”标识符的function是什么?
我正在检查一些PHP 5.3.0
function,并在网站上看到一些相当有趣的代码:
public function getTotal($tax) { $total = 0.00; $callback = /* This line here: */ 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); }
作为匿名函数的例子之一。
有人知道吗? 任何文件? 它看起来很邪恶,是否应该使用它?
这就是PHP如何expression一个闭包 。 这根本不是邪恶的,事实上它是非常有用的。
基本上这意味着你允许匿名函数“捕获”它之外的局部variables(在这种情况下, $tax
和一个对$total
的引用)并且保留它们的值(或者在$total
reference的情况下$total
本身)作为匿名函数本身的状态。
一个更简单的答案。
function ($quantity) use ($tax, &$total) { .. };
- 闭包是分配给variables的函数,所以你可以传递它
- 闭包是一个独立的命名空间,通常你不能访问在这个命名空间之外定义的variables。 有关键字use :
- 使用允许您访问(使用)闭包中的后续variables。
- 使用是早期绑定。 这意味着variables值在定义闭包时被复制。 所以在闭包里修改
$tax
是没有外部效果的,除非它是一个指针,就像一个对象一样。 - 您可以像
&$total
一样传递variables作为指针。 这样,修改$total
的值就会有一个外部效应,原来的variables值会改变。 - 闭合内部定义的variables也不能从闭合外部访问。
- closures和function具有相同的速度。 是的,你可以在你的脚本中使用它们。
正如@Mytskine 指出的,最好的深入解释是closures的RFC 。 (Upvote他为此。)
封闭是美丽的! 他们解决了许多匿名函数带来的问题,并且使得优雅的代码成为可能(至less只要我们谈论php)。
JavaScript程序员总是使用闭包,有时甚至不知道它,因为绑定variables没有明确定义 – 这就是“使用”是在PHP中。
比上面的例子有更好的现实世界的例子。 可以说你必须通过一个子值对multidimensional array进行sorting,但是键的改变。
<?php function generateComparisonFunctionForKey($key) { return function ($left, $right) use ($key) { if ($left[$key] == $right[$key]) return 0; else return ($left[$key] < $right[$key]) ? -1 : 1; }; } $myArray = array( array('name' => 'Alex', 'age' => 70), array('name' => 'Enrico', 'age' => 25) ); $sortByName = generateComparisonFunctionForKey('name'); $sortByAge = generateComparisonFunctionForKey('age'); usort($myArray, $sortByName); usort($myArray, $sortByAge); ?>
警告:未经testing的代码(我没有安装atm的php5.3),但应该看起来像这样的东西。
有一个缺点:很多PHP开发者可能会有点无奈,如果你面对封锁他们。
为了更好地理解闭包的好处,我会给你另一个例子 – 这一次在JavaScript。 其中一个问题是范围和浏览器固有的asynchronous性。 特别是,如果涉及到window.setTimeout();
(或间隔)。 所以,你传递一个函数setTimeout,但是你不能给任何参数,因为提供参数执行代码!
function getFunctionTextInASecond(value) { return function () { document.getElementsByName('body')[0].innerHTML = value; // "value" is the bound variable! } } var textToDisplay = prompt('text to show in a second', 'foo bar'); // this returns a function that sets the bodys innerHTML to the prompted value var myFunction = getFunctionTextInASecond(textToDisplay); window.setTimeout(myFunction, 1000);
myFunction返回一个具有一种预定义参数的函数!
说实话,自5.3以来,我更喜欢PHP和匿名函数/closures。 命名空间可能更重要, 但是它们性感不如以前 。
function () use () {}
是PHP的closures,你必须使用use
来包含父function
variables。
<?php $message = "hello\n"; $example = function () { echo $message; }; // Notice: Undefined variable: message $example(); $example = function () use ($message) { echo $message; }; // "hello" $example(); // Inherited variable's value is from when the function is defined, not when called $message = "world\n"; // "hello" $example(); // Inherit by-reference $message = "hello\n"; $example = function () use (&$message) { echo $message; }; // "hello" $example(); // The changed value in the parent scope is reflected inside the function call $message = "world\n"; // "world" $example(); // Closures can also accept regular arguments $example = function ($arg) use ($message) { echo $arg . ' ' . $message; }; // "hello world" $example("hello");
Zupa做了一个很好的工作,解释了与“使用”的closures,以及EarlyBinding和引用“使用”的variables之间的区别。
所以我做了一个代码示例,用一个variables(=拷贝)的早期绑定:
<?php $a = 1; $b = 2; $closureExampleEarlyBinding = function() use ($a, $b){ $a++; $b++; echo "Inside \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "Inside \$closureExampleEarlyBinding() \$b = ".$b."<br />"; }; echo "Before executing \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "Before executing \$closureExampleEarlyBinding() \$b = ".$b."<br />"; $closureExampleEarlyBinding(); echo "After executing \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "After executing \$closureExampleEarlyBinding() \$b = ".$b."<br />"; /* this will output: Before executing $closureExampleEarlyBinding() $a = 1 Before executing $closureExampleEarlyBinding() $b = 2 Inside $closureExampleEarlyBinding() $a = 2 Inside $closureExampleEarlyBinding() $b = 3 After executing $closureExampleEarlyBinding() $a = 1 After executing $closureExampleEarlyBinding() $b = 2 */ ?>
引用variables的示例(注意variables前的“&”字符);
<?php $a = 1; $b = 2; $closureExampleReferencing = function() use (&$a, &$b){ $a++; $b++; echo "Inside \$closureExampleReferencing() \$a = ".$a."<br />"; echo "Inside \$closureExampleReferencing() \$b = ".$b."<br />"; }; echo "Before executing \$closureExampleReferencing() \$a = ".$a."<br />"; echo "Before executing \$closureExampleReferencing() \$b = ".$b."<br />"; $closureExampleReferencing(); echo "After executing \$closureExampleReferencing() \$a = ".$a."<br />"; echo "After executing \$closureExampleReferencing() \$b = ".$b."<br />"; /* this will output: Before executing $closureExampleReferencing() $a = 1 Before executing $closureExampleReferencing() $b = 2 Inside $closureExampleReferencing() $a = 2 Inside $closureExampleReferencing() $b = 3 After executing $closureExampleReferencing() $a = 2 After executing $closureExampleReferencing() $b = 3 */ ?>
$tax
和$total
的范围在函数getTotal()内 。 你正在调用里面的callback函数。 所以没有必要打电话use
。