2015-11-15 2 views
1

Учитывая этот код в JavaScript:Weird поведение закрытия в PHP

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!

Почему они не работают одинаково? Что-то не так с кодом?

+0

Я бы назвал это «неожиданное» вместо «странно ';) – moorscode

+1

Хотя это интересный теоретический вопрос, я бы сказал, что ни один из ваших примеров не очень ясен в передаче намерений кода. – Sven

ответ

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

Надеется, что это помогает :) х

+1

Боюсь, что в вашем комментарии явно не указано, в чем основное отличие. На других языках, таких как C# и закрытие JavaScript, наследуется область функций (все переменные, объявленные в области функций). При закрытии PHP наследует только область объекта ($ this). Если бы он изменил $ var на $ this-> var, то код работал бы так, как ожидалось. Очевидно, что использовать переменную из функции scope - это то, что вы написали, используя ссылку, потому что она примитивна. Но это связано с тем, что использование не объявляет, какие переменные должны передаваться в область видимости, а скорее указывает, какие переменные должны быть скопированы в закрытие. – takwlasnie

1

Вы должны пройти $ вар как ссылка на вашу подфункцию, амперсанды

$inc = function($num) use (&$var) { 
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); 
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); 
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

Смежные вопросы