Nowości w PHP 8.2 - Readonly Classes, DNF Types i Standalone Types
PHP 8.2, wydany 8 grudnia 2022 roku, wprowadza kolejne znaczące usprawnienia języka. Wśród najważniejszych nowości znajdują się klasy readonly, typy DNF (Disjunctive Normal Form) oraz standalone types null, false i true. Te dodatki czynią PHP jeszcze bardziej ekspresyjnym i bezpiecznym językiem.
Dlaczego PHP 8.2?
PHP 8.2 koncentruje się na uproszczeniu kodu i zwiększeniu bezpieczeństwa typów. Wprowadza funkcje, które eliminują powtarzalny kod i pozwalają na bardziej precyzyjne definiowanie kontraktów API.
1. Readonly Classes - Klasy Tylko do Odczytu
Readonly classes automatycznie oznaczają wszystkie właściwości jako readonly. To syntactic sugar dla klas immutable, szczególnie przydatny w DTO (Data Transfer Objects) i Value Objects.
<?php
// PHP 8.2 - Readonly class
readonly class UserDTO
{
public function __construct(
public string $name,
public string $email,
public int $age,
public array $roles
) {}
}
// PHP 8.1 - każda właściwość readonly osobno
class UserDTO
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly int $age,
public readonly array $roles
) {}
}
// Użycie
$user = new UserDTO(
name: 'Jan Kowalski',
email: 'jan@example.com',
age: 30,
roles: ['admin', 'editor']
);
// OK - odczyt
echo $user->name;
// Error - próba modyfikacji
$user->age = 31; // Fatal error
2. DNF Types - Disjunctive Normal Form Types
DNF types pozwalają na łączenie union types i intersection types zgodnie ze standardem normalnej formy dysjunkcyjnej. Innymi słowy, możesz tworzyć typy w postaci OR-ów z AND-ów, gdzie intersection types muszą być w nawiasach.
<?php
interface Loggable
{
public function log(): void;
}
interface Cacheable
{
public function cache(): void;
}
interface Serializable
{
public function serialize(): string;
}
// DNF Type: (Loggable & Cacheable) lub Serializable
function process((Loggable&Cacheable)|Serializable $object): void
{
if ($object instanceof Serializable) {
$data = $object->serialize();
} else {
$object->log();
$object->cache();
}
}
// Nullable intersection type - najważniejszy przypadek użycia
function save((Loggable&Cacheable)|null $object): void
{
if ($object !== null) {
$object->log();
$object->cache();
}
}
3. Standalone Types: null, false, true
PHP 8.2 pozwala używać null, false i true jako samodzielnych typów, nie tylko w kombinacji z innymi typami. To szczególnie przydatne przy definiowaniu precyzyjnych kontraktów funkcji.
<?php
// null jako standalone type
function getConfig(string $key): mixed
{
return $this->config[$key] ?? null;
}
// false jako standalone type - funkcje walidacyjne
function validateEmail(string $email): false|array
{
$parsed = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($parsed === false) {
return false;
}
return ['email' => $parsed, 'valid' => true];
}
// true jako standalone type
function isAdmin(User $user): true
{
if (!$user->hasRole('admin')) {
throw new \Exception('User is not admin');
}
return true; // Zawsze zwraca true lub rzuca wyjątek
}
4. Random Extension - Nowe OOP API
PHP 8.2 wprowadza nowe, obiektowe API do generowania liczb losowych, które jest bardziej bezpieczne i łatwiejsze w użyciu niż stare funkcje rand() i mt_rand().
<?php
// Nowy Randomizer
$randomizer = new \Random\Randomizer();
// Losowa liczba z zakresu
$dice = $randomizer->getInt(1, 6);
// Losowe bajty
$bytes = $randomizer->getBytes(16);
// Przetasowanie tablicy
$cards = ['A', 'K', 'Q', 'J', '10', '9', '8', '7'];
$shuffled = $randomizer->shuffleArray($cards);
// Wybór losowego elementu
$winner = $randomizer->pickArrayKeys($participants, 1);
// Możesz też używać różnych silników
$secure = new \Random\Randomizer(new \Random\Engine\Secure());
$token = bin2hex($secure->getBytes(32));
5. Deprecated Dynamic Properties
PHP 8.2 oznacza dynamiczne właściwości jako deprecated (poza stdClass i __get/__set). To krok w stronę bardziej przewidywalnego i bezpiecznego kodu.
<?php
class User
{
public string $name;
}
$user = new User();
$user->name = 'Jan'; // OK
// Deprecated w PHP 8.2
$user->email = 'jan@example.com'; // Deprecation warning
// Jeśli chcesz używać dynamicznych właściwości, użyj #[AllowDynamicProperties]
#[\AllowDynamicProperties]
class FlexibleUser
{
public string $name;
}
$user = new FlexibleUser();
$user->email = 'jan@example.com'; // OK - dozwolone przez atrybut
6. SensitiveParameter Attribute - Ukrywanie Wrażliwych Danych
Atrybut #[SensitiveParameter] pozwala na ukrywanie wrażliwych danych (takich jak hasła, tokeny API) w stack trace i logach. Parametry oznaczone tym atrybutem będą wyświetlane jako "Object(SensitiveParameterValue)" zamiast rzeczywistej wartości.
<?php
function login(
string $username,
#[\SensitiveParameter] string $password
): bool {
if ($password !== 'secret123') {
throw new \Exception('Invalid password');
}
return true;
}
try {
login('admin', 'wrong_password');
} catch (\Exception $e) {
echo $e->getTraceAsString();
}
// Output w PHP 8.2:
// #0 login('admin', Object(SensitiveParameterValue))
// Hasło NIE jest wyświetlone w stack trace!
// Dla porównania PHP 8.1:
// #0 login('admin', 'wrong_password')
// Hasło jest widoczne - potencjalne zagrożenie bezpieczeństwa
// Użycie z API
class ApiClient
{
public function __construct(
private string $endpoint,
#[\SensitiveParameter] private string $apiKey
) {}
public function request(string $path): array
{
// Jeśli wystąpi błąd, apiKey nie będzie w traceback
return $this->http->get($this->endpoint . $path);
}
}
// Database connection
function connectToDatabase(
string $host,
string $database,
string $username,
#[\SensitiveParameter] string $password
): PDO {
return new PDO(
"mysql:host=$host;dbname=$database",
$username,
$password
);
}
Inne ważne nowości w PHP 8.2
- Constants in traits - możliwość definiowania stałych w traitach
- Fetch enum properties in const expressions - użycie właściwości enumów w wyrażeniach stałych
- Deprecate ${} string interpolation - przestarzała składnia interpolacji stringów
- Disjunctive Normal Form (DNF) Types - kombinacja union i intersection types
🎓 Chcesz poznać wszystkie nowości PHP?
Ten wpis to fragment kompleksowego kursu PHP 8.4, w którym szczegółowo omawiam wszystkie wersje PHP 8.x wraz z praktycznymi przykładami z rzeczywistych projektów.