Funkcje anonimowe
Funkcje anonimowe, znane także jako closures (pol. domknięcia), pozwalają
pozwalają na utworzenie funkcji, które nie mają określonej nazwy. Są najbardziej użyteczne jako
wartość parametru typu callback,
ale mają też wiele innych zastosowań.
Funkcje anonimowe są zaimplementowane przy użyciu klasy Closure.
Przykład #1 Przykład funkcji anonimowej
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// wyświetli helloWorld
?>
Domknięcia mogą zostać użyte także jako wartości zmiennych; PHP automatycznie
konwertuje takie wyrażenia na instancje
wewnętrznej klasy Closure. Przypisanie domknięcia do
zmiennej korzysta z takiej samej składni jak każde inne przypisanie, włączając w to
średnik na końcu:
Przykład #2 Przypisanie funkcji anonimowej do zmiennej
<?php
$greet = function($name)
{
printf("Witaj %s\r\n", $name);
};
$greet('Świecie');
$greet('PHP');
?>
Domknięcia mogą także dziedziczyć zmienne z zasięgu nadrzędnego. Każda taka
musi być przekazana za pomocą kontrukcji use.
Od PHP 7.1 jako takie zmienne nie mogą zostać użyte superglobals,
$this oraz zmienne o nazwach takich jak parametry.
Przykład #3 Dziedziczenie zmiennych z nadrzędnego zakresu
<?php
$message = 'hello';
// Brak "use"
$example = function () {
var_dump($message);
};
$example();
// Odziedzicz $message
$example = function () use ($message) {
var_dump($message);
};
$example();
// Wartość jest dziedziczona podczas definiowania funkcji,
// a nie jej wykonywania
$message = 'world';
$example();
// Zresetuj wiadomosć
$message = 'hello';
// Odziedzicz przez referencje
$example = function () use (&$message) {
var_dump($message);
};
$example();
// Zmieniona wartość w zasięgu nadrzędnym jest
// brana pod uwagę wewnątrz wywołania funkcji
$message = 'world';
$example();
// Domknięcia mogą także przyjmować normalne argumenty
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
?>
Powyższy przykład wyświetli coś
podobnego do:
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
Dziedziczenie zmiennych z zasięgu nadrzędnego to nie
to samo co użycie zmiennych globalnych.
Zmienne globalne istnieją w zasięgu globalnym, który jest jednakowy
bez względu na wykonywaną funkcję. Nadrzędnym zasięgiem domknięcia jest
funkcja, w której domknięcie zostało zadeklarowane (niekoniecznie funkcja,
z której zostało wykonane). Zobacz poniższy przykład:
Przykład #4 Domknięcia i zasięg
<?php
// Podstawowy koszyk sklepowy, który zawiera listę dodanych produktów
// i ilość każdego z nich. Zawiera metodę, która
// liczy całkowitą cenę produktów w koszyku używając
// funkcji anonimowej jako callbacku.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
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);
}
}
$my_cart = new Cart;
// Dodaj produkty do koszyka
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Wyświetl całkowitą cenę z 5% podatkiem.
print $my_cart->getTotal(0.05) . "\n";
// Wynik to 54.29
?>
Przykład #5 Automatyczne przypisanie $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
Powyższy przykład wyświetli:
Powyższy przykład w PHP 5.3 wyświetli:
Notice: Undefined variable: this in script.php on line 8
NULL
Od PHP 5.4.0, gdy funkcja anonimowa jest zadeklarowana w kontekście klasy,
obecna klasa jest automatycznie do niej przypisywana, sprawiając że w zakresie
funkcji jest dostępna zmienna $this. Jeśli to automatyczne
powiązywanie jest niepożądane, można w zamian użyć
statycznych funkcji
anonimowych.
Statyczne funkcje anonimowe
Od PHP 5.4 funkcje anonimowe mogą być zadeklarowane jako statyczne.
Zapobiega to przed automatycznym przypisaniem do nich obecnej klasy.
Nie można też przypisać do nich obiektów w czasie wykonywania skryptu.
Przykład #6 Próba użycia $this wewnątrz statycznej funkcji anonimowej
<?php
class Foo {
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Powyższy przykład wyświetli:
Notice: Undefined variable: this in %s on line %d
NULL
Przykład #7 Próba przypisania obiektu do statycznej funkcji anonimowej
<?php
$func = static function() {
// ciało funkcji
};
$func = $func->bindTo(new StdClass);
$func();
?>
Powyższy przykład wyświetli:
Warning: Cannot bind an instance to a static closure in %s on line %d