PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP 8.5 RFC – pipe operator, readonly dziedziczenie, generics dlaczego nie ma

by Henryk Tews / wtorek, 04 lutego 2025 / Opublikowano w PHP

PHP 8.5 wyjdzie prawdopodobnie w listopadzie 2025. Proces RFC jest otwarty i kilka interesujących propozycji jest już w dyskusji lub głosowaniu. Przeglądam co ma realną szansę wejść, co jest wciąż dyskutowane i czego PHP developerzy najbardziej oczekują. Żadnych fake predictions – tylko to co widać w Internals liście i wiki.php.net.

Jak działa proces RFC w PHP

Każda zmiana w PHP przechodzi przez formalny RFC (Request for Comments) na wiki.php.net. RFC wymaga dyskusji przez minimum 2 tygodnie a następnie głosowania – 2/3 głosów „za” żeby przeszło. Core PHP Internals to ~20 aktywnych developerów którzy mają prawo głosu. Śledzę listę mailingową php-internals@lists.php.net i wiki.php.net/rfc jako podstawowe źródła.

Pipe Operator |> – po raz kolejny w dyskusji

Pipe operator to jedna z najbardziej pożądanych funkcji PHP – i jedna z najdłużej dyskutowanych bez finału. Po kolejnym RFC w 2024 jest szansa że 2025 będzie rokiem przełomu:

<?php

declare(strict_types=1);

// Bez pipe operator - zagnieżdżone wywołania lub zmienne tymczasowe
$result = array_filter(
    array_map(
        fn($item) => strtolower(trim($item)),
        explode(',', $input)
    ),
    fn($item) => strlen($item) > 2
);

// Lub z tymczasowymi zmiennymi - czytelniej ale verbose
$items    = explode(',', $input);
$trimmed  = array_map(fn($i) => strtolower(trim($i)), $items);
$filtered = array_filter($trimmed, fn($i) => strlen($i) > 2);

// Z pipe operator (jeśli przejdzie RFC) - sekwencyjny, czytelny
$result = $input
    |> explode(',', $$)
    |> array_map(fn($i) => strtolower(trim($i)), $$)
    |> array_filter($$, fn($i) => strlen($i) > 2);

// Realny przykład w kontekście przetwarzania danych produktów
$processedSkus = $rawInput
    |> trim($$)
    |> strtoupper($$)
    |> preg_replace('/[^A-Z0-9\-]/', '', $$)
    |> array_filter([$$], fn($s) => strlen($s) >= 3)[0] ?? null;

Aktualny status: RFC jest w fazie discussion, nie voting. Główna przeszkoda to składnia – różne frakcje preferują różne formy (|> vs ->> vs partial application). Ostrożny optymizm na 2025.

Readonly klasy z dziedziczeniem – potencjalna zmiana

<?php

declare(strict_types=1);

// Aktualnie (PHP 8.2-8.4): readonly class nie może dziedziczyć po niereadonly
readonly class Address
{
    public function __construct(
        public string $street,
        public string $city,
        public string $postcode
    ) {}
}

// To jest BŁĄD w PHP 8.4:
class ExtendedAddress extends Address  // Fatal Error!
{
    public function __construct(
        string $street,
        string $city,
        string $postcode,
        public string $country = 'PL'  // dodatkowe pole
    ) {
        parent::__construct($street, $city, $postcode);
    }
}

// RFC proponuje: readonly extends readonly - ok
readonly class InternationalAddress extends Address
{
    public function __construct(
        string $street,
        string $city,
        string $postcode,
        public readonly string $country = 'PL'
    ) {
        parent::__construct($street, $city, $postcode);
    }
}

// Jeśli RFC przejdzie - Value Object hierarchie staną się możliwe

Named Arguments w define() i stałych

<?php

// Mniejszy RFC ale przydatny - named arguments w większej liczbie kontekstów
// Aktualnie niektóre wbudowane funkcje nie obsługują named args

// Proponowane rozszerzenie zasięgu named arguments na:
// - wszystkie funkcje wbudowane uniformly
// - stałe wyrażenia (const contexts)

// Przykład który działa dziś:
$filtered = array_filter($items, callback: fn($i) => $i > 0);

// Przykład który może nie działać (zależy od funkcji):
// $formatted = number_format(num: 1234567.89, decimals: 2, decimal_separator: ',', thousands_separator: ' ');
// Ta funkcja ma stare nazwy parametrów które PHP 8.4 już poprawia

Typed Constants in Interfaces – rozszerzenie z PHP 8.3

<?php

declare(strict_types=1);

// PHP 8.3 dodało typed constants w klasach
// RFC na 8.5 proponuje rozszerzenia:

// 1. Typed constants w Enum (aktualnie brak)
enum Status: string
{
    // Aktualnie enum nie może mieć typed constants obok case'ów
    // RFC proponuje:
    const string DEFAULT = self::Active->value; // możliwe w 8.5?

    case Active   = 'active';
    case Inactive = 'inactive';
}

// 2. Readonly typed constants (immutable after definition)
class Config
{
    const readonly string VERSION = '2.4.8'; // RFC: readonly modifier dla stałych?
    // W PHP 8.3 stałe są już de facto readonly - to bardziej explicit marker
}

Czego developerzy oczekują najbardziej – ankieta społeczności

JetBrains coroczna ankieta „State of Developer Ecosystem” i dyskusje na reddit/r/PHP pokazują spójny obraz oczekiwań:

Feature Szansa na PHP 8.5 Komentarz
Pipe operator |> Średnia Wieloletnia dyskusja, może w końcu przejść
Generics / Templates Niska Brak RFC który zebrałby konsensus
Readonly class dziedziczenie Wysoka Logiczne uzupełnienie PHP 8.2 feature
First-class callable syntax poprawki Wysoka Drobne ale użyteczne usprawnienia
Pattern matching Niska match() już jest, pełny pattern matching to duże RFC
Async/await natywnie Brak Fibers to foundation, ale natywny async to lata pracy

Generics – dlaczego PHP ich nie ma i czy kiedyś będzie

Generics to najczęściej wymieniana brakująca funkcja PHP. PHPStan i Psalm symulują je przez docblock (@template T), ale to nie jest wsparcie na poziomie języka. Problem jest fundamentalny:

<?php

// Generics przez PHPStan templates - działa dla statycznej analizy
/**
 * @template T
 */
class Collection
{
    /** @var T[] */
    private array $items = [];

    /**
     * @param T $item
     */
    public function add(mixed $item): void
    {
        $this->items[] = $item;
    }

    /**
     * @return T|null
     */
    public function first(): mixed
    {
        return $this->items[0] ?? null;
    }
}

// PHPStan wie że to Collection
/** @var Collection $products */
$products = new Collection();
$products->add(new Product()); // ok
$products->add(new Order());   // PHPStan error!

$product = $products->first(); // PHPStan wie że to Product

// Problem: PHP engine nie weryfikuje typów w runtime
// Implementacja natywnych generics wymagałaby zmian w samym engine
// i jest technicznie znacznie trudniejsza niż dodanie nowej składni

Nikita Popov (jeden z głównych architektów PHP 8.x) napisał szczegółowo dlaczego generics w PHP są trudne technicznie. Krótko: reified generics (jak w Java) wymagają zmian w engine, erased generics (jak TypeScript) dają korzyści tylko przy statycznej analizie. PHP ma już drugie przez PHPStan/Psalm bez zmian w engine. Stąd niski priorytet.

Co obserwuję w php-internals

Kilka RFC które są w aktywnej dyskusji na początku 2025 i mają szansę na głosowanie przed Feature Freeze (jesień 2025):

  • Deprecated dynamic properties cleanup – usunięcie AllowDynamicProperties behavior w PHP 9.0, ale deprecation w 8.5
  • Array unpacking z string keys – rozszerzenie spread operatora
  • Closure::bind improvements – drobne ergonomiczne poprawki
  • Intersection types w więcej kontekstach – rozszerzenie PHP 8.1 feature

Podsumowanie

PHP 8.5 będzie ewolucją, nie rewolucją – jak przystało na wersję minor w dojrzałym języku. Pipe operator byłby największą zmianą jeśli przejdzie RFC. Readonly inheritance uzupełni logikę z 8.2. Generics pozostają marzeniem na papierze. Śledzę php-internals na bieżąco – zaktualizowany przegląd pojawi się gdy Feature Freeze zbliży się jesienią.

About Henryk Tews

Co możesz przeczytać następne

PHP 8.5 RC1 – pipe operator w realnym kodzie, pułapki, readonly dziedziczenie potwierdzone
Drupal 10 – Entity Types, hooks, DI, headless przez JSON:API, porównanie z WP i Magento
PHP Fibers deep dive – własny scheduler, kooperatywna wielozadaniowość, równoległe HTTP
  • 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}