Anonymous functions
Anonieme functies
Anonieme functies, ook wel bekend als `closures`, stellen je in staat om functies te creëren zonder een gespecificeerde naam. Ze zijn het nuttigst als de waarde van `callable` parameters, maar ze hebben veel andere toepassingen.
Anonieme functies worden geïmplementeerd met behulp van de `Closure` klasse.
Voorbeeld: Voorbeeld van een anonieme functie
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
?>
Closures kunnen ook worden gebruikt als de waarden van variabelen; PHP converteert dergelijke expressies automatisch in instanties van de interne `Closure` klasse. Het toewijzen van een closure aan een variabele gebruikt dezelfde syntaxis als elke andere toewijzing, inclusief de afsluitende puntkomma:
Voorbeeld: Voorbeeld van toewijzing van een anonieme functie aan een variabele
<?php
$greet = function($name) {
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
Closures kunnen ook variabelen uit de bovenliggende scope overnemen. Alle dergelijke variabelen moeten worden doorgegeven aan de `use` taalconstructie. Vanaf PHP 7.1 mogen deze variabelen geen `$this`, superglobals of variabelen met dezelfde naam als een parameter bevatten. Een return type declaratie van de functie moet *na* de `use` clausule worden geplaatst.
Voorbeeld: Variabelen overnemen uit de bovenliggende scope
<?php
$message = 'hello';
// Geen "use"
$example = function () {
var_dump($message);
};
$example();
// Neem $message over
$example = function () use ($message) {
var_dump($message);
};
$example();
// De waarde van de overgenomen variabele is van wanneer de functie
// is gedefinieerd, niet wanneer deze wordt aangeroepen
$message = 'world';
$example();
// Reset bericht
$message = 'hello';
// Overnemen bij referentie
$example = function () use (&$message) {
var_dump($message);
};
$example();
// De gewijzigde waarde in de bovenliggende scope
// wordt weerspiegeld binnen de functieaanroep
$message = 'world';
$example();
// Closures kunnen ook reguliere argumenten accepteren
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
// Return type declaratie komt na de use clausule
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
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"
string(11) "hello world"
Vanaf PHP 8.0.0 mag de lijst van scope-overgenomen variabelen een afsluitende komma bevatten, die zal worden genegeerd.
Het overnemen van variabelen uit de bovenliggende scope is hetzelfde als het gebruik van globale variabelen. Globale variabelen bestaan in de globale scope, die hetzelfde is, ongeacht welke functie wordt uitgevoerd. De bovenliggende scope van een closure is de functie waarin de closure is gedeclareerd (niet noodzakelijkerwijs de functie waaruit deze is aangeroepen). Zie het volgende voorbeeld:
Voorbeeld: Closures en scoping
<?php
// Een basis winkelwagentje dat een lijst van toegevoegde producten bevat
// en de hoeveelheid van elk product. Bevat een methode die
// de totale prijs van de artikelen in het wagentje berekent met behulp van een
// closure als callback.
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;
// Voeg enkele artikelen toe aan het wagentje
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Print het totaal met een 5% verkoopbelasting.
print $my_cart->getTotal(0.05) . "\n";
// Het resultaat is 54.29
?>
Voorbeeld: Automatische binding van $this
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
object(Test)#1 (0) {
}
Wanneer gedeclareerd in de context van een klasse, wordt de huidige klasse automatisch aan het object gebonden, waardoor `$this` beschikbaar is binnen de scope van de functie. Als deze automatische binding van de huidige klasse niet gewenst is, kan in plaats daarvan een statische anonieme functie worden gebruikt.
Statische anonieme functies
Anonieme functies kunnen statisch worden gedeclareerd. Dit voorkomt dat ze automatisch aan de huidige klasse worden gebonden. Objecten kunnen ook niet aan hen worden gebonden tijdens runtime.
Voorbeeld: Poging om $this te gebruiken binnen een statische anonieme functie
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Notice: Undefined variable: this in %s on line %d
NULL
Voorbeeld: Poging om een object aan een statische anonieme functie te binden
<?php
$func = static function() {
// function body
};
$func = $func->bindTo(new stdClass);
$func();
?>
Warning: Cannot bind an instance to a static closure in %s on line %d
Opmerking: > Het is mogelijk om
func_num_args,func_get_arg, enfunc_get_argsvanuit een closure te gebruiken.