在PHP 5.3.0中,“use”标识符的function是什么?

我正在检查一些PHP 5.3.0function,并在网站上看到一些相当有趣的代码:

 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) { .. };

  1. 闭包是分配给variables的函数,所以你可以传递它
  2. 闭包是一个独立的命名空间,通常你不能访问在这个命名空间之外定义的variables。 有关键字use
  3. 使用允许您访问(使用)闭包中的后续variables。
  4. 使用是早期绑定。 这意味着variables值在定义闭包时被复制。 所以在闭包里修改$tax是没有外部效果的,除非它是一个指针,就像一个对象一样。
  5. 您可以像&$total一样传递variables作为指针。 这样,修改$total的值就会有一个外部效应,原来的variables值会改变。
  6. 闭合内部定义的variables也不能从闭合外部访问。
  7. 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来包含父functionvariables。

 <?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