PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP 8.4 preview – property hooks, asymmetric visibility, chaining new

by Henryk Tews / wtorek, 09 stycznia 2024 / Opublikowano w PHP

PHP 8.4 planowane jest na listopad 2024 i ma przynieść dwie zmiany które zmienią sposób pisania klas PHP – property hooks i asymmetric visibility. Property hooks to coś czego brakowało od lat: możliwość definiowania logiki get/set bezpośrednio przy właściwości, bez osobnych metod. Asymmetric visibility pozwala na readonly-like zachowanie z możliwością wewnętrznej modyfikacji. Przeglądam RFC które przeszły głosowanie.

Property Hooks – get i set przy właściwości

Do PHP 8.4 jeśli chciałeś kontrolować odczyt lub zapis właściwości, pisałeś gettery i settery. Property hooks przenoszą tę logikę bezpośrednio do deklaracji właściwości:

<?php

declare(strict_types=1);

// Przed PHP 8.4 - klasyczne gettery/settery
class Product
{
    private float $_price;
    private string $_name;

    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 = round($price, 2);
    }

    public function getName(): string
    {
        return $this->_name;
    }

    public function setName(string $name): void
    {
        $this->_name = trim($name);
    }
}
<?php

declare(strict_types=1);

// PHP 8.4 - property hooks eliminują boilerplate
class Product
{
    // Hook get i set bezpośrednio przy właściwości
    public float $price {
        get {
            return $this->price;
        }
        set(float $value) {
            if ($value < 0) {
                throw new \InvalidArgumentException('Price cannot be negative');
            }
            $this->price = round($value, 2);
        }
    }

    public string $name {
        // Skrócona forma dla prostych transformacji
        get => trim($this->name);
        set => trim($value);
    }

    // Tylko get hook - właściwość computed, bez zapisu
    public string $slug {
        get => strtolower(str_replace(' ', '-', $this->name));
    }

    public function __construct(string $name, float $price)
    {
        $this->name  = $name;  // wywołuje hook set
        $this->price = $price; // wywołuje hook set
    }
}

$product = new Product('  Widget Pro  ', 29.999);
echo $product->name;  // Widget Pro (trimmed)
echo $product->price; // 30.0 (rounded)
echo $product->slug;  // widget-pro (computed)

$product->price = -5.0; // InvalidArgumentException

Property Hooks w interfejsach

<?php

declare(strict_types=1);

// Interfejsy mogą deklarować wymagane hooki
interface ProductInterface
{
    // Wymaga implementacji hooka get i set dla price
    public float $price { get; set; }

    // Wymaga tylko hooka get (computed property)
    public string $slug { get; }
}

// Implementacja musi dostarczyć zadeklarowane hooki
class SimpleProduct implements ProductInterface
{
    public float $price {
        get => $this->_price;
        set => $this->_price = max(0.0, round($value, 2));
    }

    public string $slug {
        get => strtolower(str_replace(' ', '-', $this->name));
    }

    private float $_price = 0.0;

    public function __construct(
        public string $name,
        float $price
    ) {
        $this->price = $price;
    }
}

Asymmetric Visibility

Asymmetric visibility pozwala ustawić różną widoczność dla odczytu i zapisu właściwości. Rozwiązuje problem readonly – chcesz żeby właściwość była publiczna do odczytu, ale modyfikowalna tylko wewnątrz klasy:

<?php

declare(strict_types=1);

class Order
{
    // public odczyt, private zapis - zamiast readonly + metod
    // Składnia: widoczność_odczytu(widoczność_zapisu)
    public private(set) int $id;
    public private(set) string $status = 'pending';
    public protected(set) float $total = 0.0;
    public private(set) array $items = [];

    public function __construct(int $id)
    {
        $this->id = $id; // ok - jesteśmy wewnątrz klasy
    }

    public function addItem(array $item): void
    {
        $this->items[]  = $item;          // ok - private(set) dostępne w klasie
        $this->total   += $item['price'];  // ok
    }

    public function process(): void
    {
        $this->status = 'processing'; // ok - modyfikacja wewnątrz klasy
    }
}

class ExtendedOrder extends Order
{
    public function applyDiscount(float $percent): void
    {
        // protected(set) - dostępne w podklasie
        $this->total *= (1 - $percent / 100);
    }
}

$order = new Order(42);
echo $order->id;     // ok - public odczyt
echo $order->status; // ok - public odczyt
echo $order->total;  // ok - public odczyt

$order->id     = 99; // Error: Cannot modify private(set) property from outside
$order->status = 'cancelled'; // Error: Cannot modify private(set) property from outside

Porównanie readonly vs asymmetric visibility

<?php

declare(strict_types=1);

// readonly - można ustawić tylko raz, nigdy nie zmienić
readonly class ImmutableConfig
{
    public function __construct(
        public string $apiKey,
        public string $endpoint
    ) {}
    // Nie można zmodyfikować po inicjalizacji - nigdy
}

// asymmetric visibility - można modyfikować wewnątrz, nie z zewnątrz
class MutableInternally
{
    public private(set) string $status = 'draft';

    public function publish(): void
    {
        $this->status = 'published'; // ok - modyfikacja wewnątrz
    }
}

// Różnica: readonly = nigdy nie zmienisz po new
//           private(set) = możesz zmieniać wewnątrz klasy wielokrotnie

Inne nowości w PHP 8.4

<?php

// Chaining new bez nawiasów
// Przed PHP 8.4
$result = (new MyBuilder())->setFoo('bar')->build();

// PHP 8.4 - nawiasy niewymagane przy new + chain
$result = new MyBuilder()->setFoo('bar')->build();

// array_find() dostępne od PHP 8.4 (przesunięte z 8.3 RFC)
$found = array_find($products, fn($p) => $p['price'] > 100);

// Nowe funkcje bcmath
$sum = bcadd('1.234567890', '9.876543210', scale: 9);

// Lazy Objects - obiekty tworzone dopiero przy pierwszym użyciu właściwości
// (nowe API Reflection - szczegóły w dokumentacji PHP 8.4)

Kiedy to trafi do Magento 2?

Magento 2 wspiera nowe wersje PHP zwykle 6-12 miesięcy po ich premierze. PHP 8.4 (listopad 2024) prawdopodobnie oficjalnie pojawi się w Magento 2.4.8 lub 2.4.9 (2025). Można używać PHP 8.4 features w własnym kodzie modułów wcześniej, ale trzeba pamiętać że moduł nie będzie wtedy kompatybilny z PHP 8.3.

Podsumowanie

Property hooks to największa zmiana w sposobie pisania klas PHP od readonly properties. Eliminują gettery i settery przy jednoczesnym zachowaniu enkapsulacji – kod jest krótszy i czytelniejszy. Asymmetric visibility rozwiązuje realne ograniczenie readonly – teraz można mieć właściwość publiczną do odczytu i modyfikowalną wewnętrznie. Razem te dwie zmiany znacząco odchudzą typowe klasy domenowe w PHP 8.4.

About Henryk Tews

Co możesz przeczytać następne

ReactPHP – event loop, równoległe HTTP requests, serwer HTTP, Fibers bridge
PHP 8.5 RFC – pipe operator, readonly dziedziczenie, generics dlaczego nie ma
PHP Enumeracje zaawansowane – backed enums, metody, interfejsy, Magento 2
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}