PHP 8.4 jest dostępny od listopada 2024. Przynosi property hooks – natywną implementację getterów i setterów bez boilerplate, asymetryczną widoczność właściwości (public private(set)), nowe funkcje tablic i deprecację funkcji które nie były dotykane od PHP 4. To ewolucja która pozwala pisać bardziej zwięzły kod bez rezygnacji z enkapsulacji.
Property hooks – natywne gettery i settery
<?php
declare(strict_types=1);
// PHP 8.3: klasa z boilerplate getterów/setterów
class OrderItem83
{
private float $price;
private int $qty;
public function getPrice(): float { return $this->price; }
public function setPrice(float $price): void
{
if ($price < 0) throw new \InvalidArgumentException('Price cannot be negative');
$this->price = $price;
}
public function getQty(): int { return $this->qty; }
public function setQty(int $qty): void
{
if ($qty < 1) throw new \InvalidArgumentException('Qty must be positive');
$this->qty = $qty;
}
public function getTotal(): float { return $this->price * $this->qty; }
}
// PHP 8.4: property hooks - logika bezpośrednio przy właściwości
class OrderItem84
{
public float $price {
set(float $value) {
if ($value < 0) throw new \InvalidArgumentException('Price cannot be negative');
$this->price = $value;
}
get => $this->price;
}
public int $qty {
set(int $value) {
if ($value < 1) throw new \InvalidArgumentException('Qty must be positive');
$this->qty = $value;
}
}
// Hook tylko get - wirtualna właściwość obliczana
public float $total {
get => $this->price * $this->qty;
}
}
$item = new OrderItem84();
$item->price = 99.99; // wywołuje set hook
$item->qty = 3;
echo $item->total; // wywołuje get hook: 299.97
// $item->total = 100; // Fatal error: właściwość z samym get jest readonly
Asymetryczna widoczność właściwości
<?php
declare(strict_types=1);
// PHP 8.4: public właściwość którą tylko klasa może modyfikować
class Product
{
public private(set) string $sku;
public private(set) float $price;
public protected(set) int $stock; // tylko klasa i dzieci mogą ustawiać
public function __construct(string $sku, float $price, int $stock)
{
$this->sku = $sku;
$this->price = $price;
$this->stock = $stock;
}
public function applyDiscount(float $percent): void
{
$this->price = $this->price * (1 - $percent / 100); // OK - wewnątrz klasy
}
public function reserveStock(int $qty): void
{
if ($qty > $this->stock) throw new \RuntimeException('Not enough stock');
$this->stock -= $qty;
}
}
$product = new Product('SKU-001', 100.0, 50);
echo $product->sku; // OK - public read
echo $product->price; // OK - public read
echo $product->stock; // OK - public read
$product->price = 50; // Fatal error: Cannot modify private(set) property
// $product->sku = 'X'; // Fatal error
$product->applyDiscount(10); // OK - wewnątrz klasy
echo $product->price; // 90.0
Nowe funkcje tablic – array_find() i spółka
<?php
declare(strict_types=1);
$orders = [
['id' => 1, 'status' => 'complete', 'total' => 150.0],
['id' => 2, 'status' => 'pending', 'total' => 89.99],
['id' => 3, 'status' => 'processing', 'total' => 230.0],
['id' => 4, 'status' => 'pending', 'total' => 45.0],
];
// PHP 8.4: array_find() - pierwszy element spełniający warunek
$firstPending = array_find($orders, fn($o) => $o['status'] === 'pending');
// ['id' => 2, 'status' => 'pending', 'total' => 89.99]
// PHP 8.4: array_find_key() - klucz pierwszego pasującego elementu
$key = array_find_key($orders, fn($o) => $o['total'] > 200);
// 2 (indeks zamówienia z total 230)
// PHP 8.4: array_any() - czy jakikolwiek element spełnia warunek
$hasPending = array_any($orders, fn($o) => $o['status'] === 'pending');
// true
// PHP 8.4: array_all() - czy wszystkie elementy spełniają warunek
$allComplete = array_all($orders, fn($o) => $o['status'] === 'complete');
// false
// Przed PHP 8.4 wymagało array_filter + count lub foreach z break
Deprecacje i zmiany breaking
<?php
// PHP 8.4 deprecuje implicit nullable - musisz być jawny
// PHP 8.3 (działało bez ostrzeżenia):
function oldStyle(string $name = null): void {}
// PHP 8.4 (deprecated - rzuca E_DEPRECATED):
// function oldStyle(string $name = null): void {}
// PHP 8.4 (poprawnie):
function newStyle(?string $name = null): void {}
// lub:
function newStyle2(string|null $name = null): void {}
// Dotyczy wszystkich type hints - warto przejść kod przez:
// vendor/bin/phpstan analyse --level=6 app/code/
// lub rector:
// vendor/bin/rector process app/code/ --config rector.php
Podsumowanie
PHP 8.4 property hooks eliminują potrzebę pisania getterów i setterów przy zachowaniu pełnej enkapsulacji. Asymetryczna widoczność (public private(set)) pozwala mieć właściwości które są publiczne do odczytu ale prywatne do zapisu – bez dodatkowego kodu. Nowe funkcje tablic wypełniają lukę którą dotychczas zamykał się przez array_filter i foreach. Przed aktualizacją sprawdź implicit nullable – to najczęstszy problem przy migracji.
