W PHP czym jest zamknięcie i dlaczego używa identyfikatora "use"?
Sprawdzam niektóre funkcje PHP 5.3.0
i natknąłem się na jakiś kod na stronie, który wygląda dość śmiesznie:
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);
}
Jako jeden z przykładów na funkcje anonimowe.
Czy ktoś o tym wie? Jakieś dokumenty? I wygląda źle, czy powinno się go kiedyś używać?6 answers
W ten sposób PHP wyraża zamknięcie . To wcale nie jest złe i w rzeczywistości jest dość potężne i użyteczne.
Zasadniczo oznacza to, że pozwalasz funkcji anonimowej "przechwytywać" zmienne lokalne (w tym przypadku $tax
i odniesienie do $total
) poza jej zakresem i zachowujesz ich wartości (lub w przypadku $total
odniesienie do $total
) jako stan wewnątrz samej funkcji anonimowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-30 18:24:10
Prostsza odpowiedź.
function ($quantity) use ($tax, &$total) { .. };
- zamknięcie jest funkcją przypisaną do zmiennej, więc można ją przekazać
- zamknięcie jest oddzielną przestrzenią nazw, zwykle nie można uzyskać dostępu do zmiennych zdefiniowanych poza tą przestrzenią nazw. Nadchodzi użycie słowo kluczowe:
- użycie umożliwia dostęp (użycie) do kolejnych zmiennych wewnątrz zamknięcia.
-
użycie jest wcześnie wiążąca. Oznacza to, że wartości zmiennych są kopiowane podczas definiowania zamknięcia. Tak więc modyfikowanie
$tax
wewnątrz zamknięcia nie ma żadnego efektu zewnętrznego, chyba że jest wskaźnikiem, jak obiekt. - możesz przekazać zmienne jako wskaźniki, jak w przypadku
&$total
. W ten sposób modyfikowanie wartości$total
ma efekt zewnętrzny, zmienia się wartość oryginalnej zmiennej. - zmienne zdefiniowane wewnątrz zamknięcia również nie są dostępne poza zamknięciem.
- zamknięcia i funkcje mają tę samą prędkość. Tak., możesz ich używać we wszystkich skryptach.
Jak zauważył @Mytskine prawdopodobnie najlepszym szczegółowym wyjaśnieniem jestRFC dla zamknięć . / Align = "left" / )
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:00
function () use () {}
jest jak zamknięcie dla PHP.
Bez use
, funkcja nie może uzyskać dostępu do nadrzędnej zmiennej scope
$s = "hello";
$f = function () {
echo $s;
};
$f(); // Notice: Undefined variable: s
$s = "hello";
$f = function () use ($s) {
echo $s;
};
$f(); // hello
Wartość zmiennej use
pochodzi od momentu zdefiniowania funkcji, a nie od momentu wywołania
$s = "hello";
$f = function () use ($s) {
echo $s;
};
$s = "how are you?";
$f(); // hello
use
zmienna by-reference with &
$s = "hello";
$f = function () use (&$s) {
echo $s;
};
$s = "how are you?";
$f(); // how are you?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-14 02:44:44
Zamknięcia są piękne! rozwiązują one wiele problemów związanych z funkcjami anonimowymi i umożliwiają naprawdę elegancki kod (przynajmniej tak długo, jak mówimy o php).
Programiści Javascript używają zamknięć cały czas, czasami nawet nie wiedząc o tym, ponieważ powiązane zmienne nie są wyraźnie zdefiniowane - po to jest" use " w php.
Istnieją lepsze rzeczywiste przykłady niż powyższe. powiedzmy, że trzeba posortować wielowymiarową tablicę według pod-wartości, ale najważniejsze zmiany.
<?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);
?>
Warning: untested code( nie mam zainstalowanego PHP5. 3 atm), ale powinien wyglądać jak coś w tym stylu.
Jest jeden minus: wielu programistów php może być trochę bezradnych, jeśli skonfrontujesz ich z zamknięciami.
Aby lepiej zrozumieć milość zamknięć, podam kolejny przykład - tym razem w javascript. jednym z problemów jest zasięg i asynchroniczność związana z przeglądarką. szczególnie, jeśli chodzi o window.setTimeout();
(or-interval). więc ty przekaż funkcję do setTimeout, ale tak naprawdę nie możesz podać żadnych parametrów, ponieważ podanie parametrów powoduje wykonanie kodu!
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);
Mojafunction zwraca funkcję z predefiniowanym parametrem!
Szczerze mówiąc, lubię php dużo bardziej od 5.3 i anonimowych funkcji/zamknięć. przestrzenie nazw mogą być ważniejsze, , ale są o wiele mniej seksowne .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-07 14:54:41
Zupa wykonała świetną robotę wyjaśniając zamknięcia za pomocą " use "i różnicy między początkowymi a odwołującymi się do zmiennych, które są "używane".
Więc zrobiłem przykład kodu z wczesnym wiązaniem zmiennej (=kopiowanie):
<?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
*/
?>
Przykład z odwołaniem do zmiennej (zwróć uwagę na znak ' & ' przed zmienną);
<?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
*/
?>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-17 01:21:17
Do ostatnich lat PHP zdefiniował swój AST, a interpreter PHP odizolował parser od części ewaluacyjnej. Podczas wprowadzania zamknięcia, parser PHP jest wysoce połączony z ewaluacją.
Dlatego, gdy closure zostało po raz pierwszy wprowadzone do PHP, interpreter nie ma metody, aby wiedzieć, które zmienne będą używane w closure, ponieważ nie jest jeszcze przetwarzane. Więc użytkownik musi zadowolić silnik zend poprzez explicit import, odrabiając zadanie domowe, które zend powinien to zrobić.
Jest to tzw. prosty sposób w PHP.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-10 14:03:30