PHP 8.1 i 8.2 przyniosły named arguments i first-class callables – dwie funkcje które zmieniają sposób pisania kodu. Named arguments eliminują „argument order confusion” i poprawiają czytelność wywołań funkcji z wieloma parametrami. First-class callables zastępują Closure::fromCallable() i [$this, 'method'] czystą składnią func(...).
Named arguments
<?php
declare(strict_types=1);
// Bez named arguments - musisz pamiętać kolejność
array_slice($array, 0, 10, true); // Co znaczy true? (preserve_keys)
str_contains($haystack, $needle); // Który jest który?
// Z named arguments - czytelne i kolejność nie ma znaczenia
array_slice(array: $array, offset: 0, length: 10, preserve_keys: true);
// Szczególnie użyteczne przy funkcjach z wieloma opcjonalnymi parametrami:
function createProduct(
string $sku,
string $name,
float $price,
int $qty = 0,
bool $isVisible = true,
bool $isEnabled = true,
string $type = 'simple',
?int $categoryId = null,
): array {
return compact('sku', 'name', 'price', 'qty', 'isVisible', 'isEnabled', 'type', 'categoryId');
}
// Przed named arguments - musisz podać wartości pośrednie
createProduct('SKU-001', 'Widget', 99.99, 0, true, true, 'simple', 5);
// ^ qty ^ visible ^ enabled ^ type
// Z named arguments - podaj tylko to co chcesz zmienić
createProduct(
sku: 'SKU-001',
name: 'Widget',
price: 99.99,
categoryId: 5, // pomiń pośrednie parametry z domyślnymi wartościami
);
Named arguments w built-in funkcjach PHP
<?php
// htmlspecialchars z named arguments
echo htmlspecialchars(
string: $userInput,
flags: ENT_QUOTES | ENT_HTML5,
encoding: 'UTF-8',
double_encode: false
);
// array_map z named args (uwaga: PHP built-ins mają historyczne nazwy parametrów)
$doubled = array_map(
callback: fn($x) => $x * 2,
array: [1, 2, 3, 4, 5]
);
// implode - historyczna niespójność (separator może być na obu pozycjach)
// Named args rozwiązują problem:
implode(separator: ', ', array: ['a', 'b', 'c']);
// Spread named args z tablicy
function connect(string $host, int $port, string $db): void {}
$config = ['db' => 'magento', 'host' => 'localhost', 'port' => 3306];
connect(...$config); // named spread - kolejność nie ma znaczenia!
First-class callables
<?php
// PHP 8.1: first-class callable syntax
// Przed:
$closure = Closure::fromCallable('strlen');
$method = Closure::fromCallable([$this, 'processItem']);
$static = Closure::fromCallable(['MyClass', 'staticMethod']);
// Po - czystsza składnia:
$closure = strlen(...); // closure z funkcji wbudowanej
$method = $this->processItem(...); // closure z metody instancji
$static = MyClass::staticMethod(...); // closure z metody statycznej
// Praktyczne zastosowania:
class OrderProcessor
{
public function processOrders(array $orders): array
{
return array_map($this->processOrder(...), $orders);
// Zamiast: array_map([$this, 'processOrder'], $orders)
// Lub: array_map(function($o) { return $this->processOrder($o); }, $orders)
}
public function processOrder(array $order): array
{
return ['id' => $order['id'], 'processed' => true];
}
public function filterAndProcess(array $orders): array
{
return array_map(
$this->processOrder(...),
array_filter($orders, $this->isEligible(...))
);
}
private function isEligible(array $order): bool
{
return $order['status'] === 'pending' && $order['total'] > 0;
}
}
Kombinacja z pipe-style programowaniem
<?php
// Pipeline z first-class callables
class Pipeline
{
private array $stages = [];
public function pipe(callable $stage): static
{
$clone = clone $this;
$clone->stages[] = $stage;
return $clone;
}
public function process(mixed $payload): mixed
{
return array_reduce(
$this->stages,
fn($carry, $stage) => $stage($carry),
$payload
);
}
}
class OrderPipeline
{
public function __construct(
private ValidateOrderService $validator,
private CalculateTaxService $taxCalculator,
private ApplyDiscountService $discountApplier,
private NotifyService $notifier,
) {}
public function handle(array $order): array
{
return (new Pipeline())
->pipe($this->validator->validate(...))
->pipe($this->taxCalculator->calculate(...))
->pipe($this->discountApplier->apply(...))
->pipe($this->notifier->notify(...))
->process($order);
}
}
Podsumowanie
Named arguments najbardziej pomagają przy wywołaniach z wieloma opcjonalnymi parametrami i przy spread z tablicy konfiguracyjnej. First-class callables eliminują boilerplate [$this, 'method'] i poprawiają czytelność pipeline-style kodu. Razem z match expressions i enums z PHP 8.x tworzą zestaw który znacznie skraca i klaruje nowoczesny PHP.
