Intereting Posts
Регулярное выражение для выражения конца строки Функция HTML replaceWith с PHP Как я могу перенаправить ошибку 404 на пользовательскую страницу 404 с помощью Codeigniter? Почему невозможно запустить исполняемый файл с функциями exec () или system ()? Как найти причину, из-за которой mkdir терпит неудачу с PHP? Функция php mail отправляется прямо в папку нежелательной почты .htaccess в подкаталоге 'overriding' parent htaccess Как отправить электронную почту с локального сервера Wamp с помощью PHP? Сонар Добавление нового проекта Могу ли я получить имя кнопки отправки в другой форме? PHP dirname возвращает путь символической ссылки Получение ошибок «Команды не синхронизированы, вы не можете запустить команду сейчас» при выполнении хранимой процедуры в mysql / PHP Сообщение об ошибке PHP GCM MismatchSenderId Поиск радиуса GPS с Php 5 и MySQL Как создать динамический субдомен с помощью PHP и htaccess?

В PHP 5.3.0, что такое функция «использовать» идентификатор?

Я просматриваю некоторые функции PHP 5.3.0 и просматриваю какой-то код на сайте, который выглядит довольно забавно:

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

как один из примеров анонимных функций .

Кто-нибудь знает об этом? Любая документация? И это выглядит злым, если его когда-нибудь использовать?

Related of "В PHP 5.3.0, что такое функция «использовать» идентификатор?"

Так PHP выражает закрытие . Это вовсе не зло, а на самом деле оно достаточно мощное и полезное.

В основном это означает, что вы разрешаете анонимной функции «захватывать» локальные переменные (в данном случае, $tax и ссылку на $total ) за пределами области действия и сохранять их значения (или в случае $total reference to $total ) как состояние внутри самой анонимной функции.

Простой ответ.

function ($quantity) use ($tax, &$total) { .. };

  1. Закрытие – это функция, назначенная переменной, поэтому вы можете ее передать
  2. Закрытие представляет собой отдельное пространство имен, обычно вы не можете обращаться к переменным, определенным за пределами этого пространства имен. Появляется ключевое слово use :
  3. использование позволяет вам использовать (использовать) следующие переменные внутри закрытия.
  4. использование раннего связывания. Это означает, что значения переменных COPIED устанавливаются при определении закрытия. Таким образом, изменение $tax внутри закрытия не имеет внешнего эффекта, если только это не указатель, как объект.
  5. Вы можете передавать переменные как указатели, например, в случае &$total . Таким образом, изменение значения $total DOES имеет внешний эффект, значение исходной переменной изменяется.
  6. Переменные, определенные внутри закрытия, также недоступны из-за пределов закрытия.
  7. Затворы и функции имеют одинаковую скорость. Да, вы можете использовать их во всех своих сценариях.

Как отметил @Mytskine , вероятно, лучшим углубленным объяснением является RFC для закрытий . (Поднимите его за это.)

закрытие красиво! они решают много проблем, которые приходят с анонимными функциями, и делают действительно элегантный код возможным (по крайней мере, пока мы говорим о php).

Программисты javascript все время используют замыкания, иногда даже не зная об этом, потому что связанные переменные явно не определены – это то, что «использовать» для php.

есть лучшие примеры в реальном мире, чем приведенные выше. скажем, вам нужно отсортировать многомерный массив по вспомогательной величине, но ключ изменяется.

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

предупреждение: непроверенный код (у меня нет установленного php5.3 atm), но он должен выглядеть примерно так.

есть один недостаток: многие разработчики php могут быть немного беспомощными, если вы столкнетесь с ними с закрытием.

чтобы лучше понять, чем больше закрытий, я приведу еще один пример – на этот раз в javascript. Одной из проблем является область охвата и присущая браузеру асинхронность. особенно, если дело доходит до window.setTimeout(); (или -interval). поэтому вы передаете функцию 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 возвращает функцию с определенным предопределенным параметром!

Честно говоря, мне нравится php намного больше с 5.3 и анонимных функций / закрытий. пространства имен могут быть более важными, но они намного менее сексуальны .

function () use () {} является закрытием для PHP, вы должны use для включения переменной родительской function .

 <?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 проделал отличную работу, объясняя закрытие «использованием» и разницей между EarlyBinding и ссылкой на переменные, которые «используются».

Поэтому я сделал пример кода с ранним связыванием переменной (= копирование):

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

Пример со ссылкой на переменную (обратите внимание на символ «&» перед переменной);

 <?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 () . Вы вызываете функцию обратного вызова внутри него. Поэтому нет необходимости звонить.