Na tuhle novinku se v PHP čekalo roky. Verze 8.6 přináší částečnou aplikaci funkcí (partial function application) a z existující funkce si díky ní vyrobíte closure s předvyplněnými argumenty.
Doteď se musela napsat celá closure:
<?php
$naSlug = static fn (string $text): string => str_replace(' ', '-', $text);
echo $naSlug('Novinky v PHP 8.6'); // Novinky-v-PHP-8.6
Od PHP 8.6 stačí na místo chybějícího argumentu napsat ? a PHP closure vytvoří za nás:
<?php
$naSlug = str_replace(' ', '-', ?);
echo $naSlug('Novinky v PHP 8.6'); // Novinky-v-PHP-8.6
Co znamená otazník a co tři tečky?
Otazník znamená přesně jeden argument, který doplním později. Tři tečky znamenají zbytek argumentů, ať už jich je kolik chce:
<?php
class Kosik
{
public function pridat(string $zbozi, int $pocet = 1, float $sleva = 0.0): void
{
// ...
}
}
$kosik = new Kosik();
$pridatKnihu = $kosik->pridat('Kniha o PHP', ...);
$pridatKnihu(); // 1 kus, bez slevy
$pridatKnihu(3); // 3 kusy
$pridatKnihu(3, 10.0); // 3 kusy se slevou
Funguje to i s pojmenovanými argumenty:
<?php
function formatujCenu(float $castka, string $mena = 'CZK', int $desetinnaMista = 2): string
{
return number_format($castka, $desetinnaMista, ',', ' ') . ' ' . $mena;
}
$vEurech = formatujCenu(?, mena: 'EUR');
echo $vEurech(1234.5); // 1 234,50 EUR
Na co si dát bacha?
Argumenty, které vyplníte hned, se vyhodnotí už při vzniku closure, ne až při jejím zavolání. Tím se to liší od arrow funkce:
<?php
$zacatek = time();
$zaloguj = sprintf('[%d] %s', $zacatek, ?); // $zacatek se vyhodnotí teď
sleep(5);
echo $zaloguj('Hotovo'); // v hranaté závorce je čas z doby vzniku closure
A druhá věc. Každý otazník vytvoří povinný parametr, i když v původní funkci byl nepovinný. Doladilo to navazující RFC:
<?php
function priklad(mixed $a, string $b = 'výchozí') {}
$closure = priklad(?, ?);
$closure('x'); // ArgumentCountError, protože $b už je povinný
Co není možné?
<?php
// Konstruktory se částečně aplikovat nedají
$nova = new Objednavka(?);
// Za "..." už nesmí být další zástupný symbol
$f = pridat(?, ..., ?);
// Poziční "?" nesmí následovat po pojmenovaném argumentu
$g = formatujCenu(mena: 'EUR', ?);
Nefunguje to ani u funkcí, které si sahají do volajícího kontextu (compact(), extract(), func_get_arg() a get_defined_vars()).
RFC prošlo v poměru 33 : 0. Mně to dává smysl hlavně u callbacků typu array_map(), kde jsem doteď psal jednořádkové arrow funkce jenom kvůli přeskládání argumentů. Uvidíme, jestli si to týmy vezmou za své :)
Zdroj: https://wiki.php.net/rfc/partial_function_application_v2