PHP中奇怪的闭包行为

时间:2015-11-15 13:47:46

标签: php scope closures

在JavaScript中给出此代码:

function getFunc(){
    var myVar = 1;
    function inc(var1) {
        myVar = myVar + 1;
        return var1 + myVar;
    }
    return inc;
}
var inc = getFunc();
console.log(inc(5));
console.log(inc(6));

如果您在浏览器控制台中运行此代码,则会为您提供7和9。我在C#中编写了相同的代码,它给了我相同的结果:

static void Main(string[] args)
{
    var inc = GetAFunc();
    Console.WriteLine(inc(5));
    Console.WriteLine(inc(6));

    Console.ReadKey();
}

public static Func<int, int> GetAFunc()
{
    var myVar = 1;
    Func<int, int> inc = delegate(int var1)
    {
        myVar = myVar + 1;
        return var1 + myVar;
    };
    return inc;
}

但为什么不在PHP中给出相同的结果呢?

function getFunc() {
    $myVar = 1;

    $inc = function($var1) use ($myVar) {
        $myVar = $myVar + 1;
        return $var1 + $myVar;
    };

    return $inc;
}

$inc = getFunc();
echo $inc(5);
echo $inc(6);

它给了我7和8!

为什么他们不以同样的方式工作?代码有问题吗?

5 个答案:

答案 0 :(得分:9)

这是因为如果您想修改另一个范围内的变量,您需要在PHP中显式化。您可以将$var定义为&的参考,从而实现此目的。例如:use (&$var)

以下代码将为您提供预期的行为:

function test() {
  $var = 1;

  $inc = function($num) use (&$var) {
      var_dump($var);
    $var = $var + 1;
    return $num + $var;
  };

  return $inc;
}

$test = test();
echo $test(5);
echo $test(6);

希望这有助于:) x

答案 1 :(得分:4)

默认情况下,PHP传递函数参数by value,因此不会更改原始变量。

您可以通过在函数中添加&符号到变量名来更改此行为:

function test() {
  $var = 1;

  $inc = function($num) use (&$var) {
    ++$var;
    return $num + $var;
  };

  return $inc;
}

$test = test();
echo $test(5);
echo $test(6);

答案 2 :(得分:1)

您必须使用&符号

将$ var作为参考传递给您的子功能
  $inc = function($num) use (&$var) {

答案 3 :(得分:1)

您也可以在闭包中创建一个静态变量而不是创建者。 这给出了预期的结果7和9。

<?php

function test() {
    $inc = function($num) {
        static $var = 1;
        $var = $var + 1;
        return $num + $var;
    };

    return $inc;
}

$test = test();
echo $test(5);
echo $test(6);

答案 4 :(得分:1)

所有其他答案都是正确的:PHP会在use中对变量进行值传递,除非您将其作为参考传递。

以下是PHP文档中的一些权威示例:

http://php.net/manual/en/functions.anonymous.php

示例3:

$message = 'hello';

// Inherit by-reference
$example = function () use (&$message) {
    var_dump($message);
};
echo $example();

虽然做得不是很好。

示例4:

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

此页面上的最高投票评论还提到人们会忘记价值传递行为:http://php.net/manual/en/functions.anonymous.php#99287