PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP 8.5 RFC potwierdzony – pipe operator!, readonly dziedziczenie, array_first/last

by Henryk Tews / wtorek, 15 kwietnia 2025 / Opublikowano w PHP

Zbliżamy się do Feature Freeze PHP 8.5 (latem 2025). Kilka RFC przeszło głosowanie i jest już w masterze. Przeglądam co jest potwierdzone, co jest w ostatniej rundzie głosowania i które propozycje nie zebrały wymaganego 2/3 głosów. Bez spekulacji – tylko potwierdzone zmiany.

Potwierdzone – RFC przeszły głosowanie

1. Pipe Operator – w końcu!

Po latach dyskusji i kilku nieudanych próbach, RFC dla pipe operatora przeszło głosowanie w marcu 2025. Składnia |> z closures:

<?php

declare(strict_types=1);

// PHP 8.5 - pipe operator
// Wartość po lewej jest przekazywana jako pierwszy argument do callable po prawej

$result = "  hello world  "
    |> trim(...)           // trim(' hello world ') = 'hello world'
    |> strtoupper(...)     // strtoupper('hello world') = 'HELLO WORLD'
    |> str_word_count(...) // str_word_count('HELLO WORLD') = 2
;

echo $result; // 2

// Z closure dla bardziej złożonych operacji
$processedSkus = $rawInput
    |> trim(...)
    |> strtoupper(...)
    |> fn($s) => preg_replace('/[^A-Z0-9\-]/', '', $s)
    |> fn($s) => strlen($s) >= 3 ? $s : null
;

// Bardzo czytelne przetwarzanie kolekcji
$activeSkus = $products
    |> array_filter(..., fn($p) => $p->isActive())
    |> array_map(..., fn($p) => $p->getSku())
    |> array_unique(...)
    |> array_values(...)
;

// Zastępuje zagnieżdżone wywołania lub zmienne tymczasowe
// Przed:
$result = array_values(array_unique(array_map(
    fn($p) => $p->getSku(),
    array_filter($products, fn($p) => $p->isActive())
)));

2. Readonly Klasy z Dziedziczeniem

<?php

declare(strict_types=1);

// PHP 8.5 - readonly class może dziedziczyć po readonly class
readonly class Address
{
    public function __construct(
        public string $street,
        public string $city,
        public string $postcode
    ) {}

    public function format(): string
    {
        return "{$this->street}, {$this->postcode} {$this->city}";
    }
}

// PHP 8.4: Fatal Error - nie można dziedziczyć readonly po readonly
// PHP 8.5: OK - obie klasy są readonly
readonly class InternationalAddress extends Address
{
    public function __construct(
        string $street,
        string $city,
        string $postcode,
        public string $country = 'PL',
        public string $countryCode = 'PL'
    ) {
        parent::__construct($street, $city, $postcode);
    }

    public function format(): string
    {
        return parent::format() . ", {$this->country}";
    }
}

readonly class BillingAddress extends Address
{
    public function __construct(
        string $street,
        string $city,
        string $postcode,
        public string $companyName = '',
        public string $vatNumber = ''
    ) {
        parent::__construct($street, $city, $postcode);
    }
}

$address = new InternationalAddress(
    street: 'ul. Marszałkowska 1',
    city: 'Warszawa',
    postcode: '00-001',
    country: 'Polska'
);

echo $address->format(); // ul. Marszałkowska 1, 00-001 Warszawa, Polska

3. Nowe funkcje tablicowe – array_first() i array_last()

<?php

declare(strict_types=1);

// PHP 8.5 - array_first() i array_last()
// Uzupełnienie array_find() z PHP 8.4

$products = [
    ['id' => 1, 'name' => 'Widget', 'price' => 29.99],
    ['id' => 2, 'name' => 'Gadget', 'price' => 49.99],
    ['id' => 3, 'name' => 'Doohickey', 'price' => 9.99],
];

// array_first - pierwszy element (bez warunku)
// Zamiast: reset($array) lub $array[array_key_first($array)]
$first = array_first($products);
// ['id' => 1, 'name' => 'Widget', 'price' => 29.99]

// array_last - ostatni element
// Zamiast: end($array) lub $array[array_key_last($array)]
$last = array_last($products);
// ['id' => 3, 'name' => 'Doohickey', 'price' => 9.99]

// Zachowanie dla pustej tablicy
$empty = [];
var_dump(array_first($empty)); // NULL
var_dump(array_last($empty));  // NULL

// W połączeniu z array_find() z PHP 8.4 - kompletny zestaw
$cheapest    = array_find($products, fn($p) => $p['price'] < 15);
$firstItem   = array_first($products);
$lastChanged = array_last($sortedByDate);

W głosowaniu – wynik niepewny

Deprecation: implicit nullable bez ? – PHP 8.5

<?php

// RFC proponuje deprecated w 8.5, Error w 8.6/9.0
// PHP 8.4 dodał E_DEPRECATED warning
// PHP 8.5 RFC: zamienić na E_DEPRECATED + notice w dokumentacji

// Przed - działa do PHP 8.3, deprecated od 8.4
function foo(string $bar = null): void {}

// Poprawnie - zawsze tak pisz
function foo(?string $bar = null): void {}

// Jeśli RFC przejdzie - kolejne narzędzia automatycznej naprawy
// Rector już obsługuje tę transformację:
// vendor/bin/rector process src --only=\Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallRector

Co nie przeszło lub nie przejdzie

Generics – brak RFC który zebrałby konsensus techniczny. Różnica między reified (Java-style, wymaga zmian w engine) a erased (TypeScript-style, tylko compile time) nadal dzieli społeczność. PHPStan templates pozostają de facto standardem.

Async/await natywnie – Fibers z PHP 8.1 to niskopoziomowy building block, ale high-level async/await API nie ma RFC. ReactPHP i Amp 3.x robią to przez biblioteki.

Pattern matching – match() z PHP 8.0 obsługuje podstawowe przypadki. Pełny pattern matching (dekonstrukcja, guards) to prawdopodobnie PHP 9.x.

Kiedy PHP 8.5?

# Harmonogram PHP (typowy)
# Styczeń-czerwiec: RFC dyskusje i głosowania
# Lipiec: Feature Freeze - żadne nowe RFC
# Sierpień-wrzesień: Alpha, Beta
# Październik-październik: RC1, RC2, RC3
# Listopad: Final release

# PHP 8.5 spodziewane: listopad 2025

# Testowanie RC1 gdy wyjdzie:
docker pull php:8.5-rc-cli
docker run --rm php:8.5-rc-cli php -v

# Sprawdź czy Twój kod jest kompatybilny z RC
docker run --rm -v $(pwd):/app php:8.5-rc-cli \
    php /app/vendor/bin/phpstan analyse --level=8 /app/src

Magento 2 i PHP 8.5

Jeśli historia się powtarza: PHP 8.5 (listopad 2025) → Magento 2.4.9 z oficjalnym wsparciem (~Q2 2026). Własny kod modułów można pisać pod PHP 8.5 wcześniej, ale zalecam trzymanie się 8.4 dla Magento projektów do momentu oficjalnego wsparcia.

Pipe operator będzie szczególnie przydatny przy przetwarzaniu kolekcji Magento:

<?php

// PHP 8.5 pipe operator w kontekście Magento 2
$activeProductSkus = $this->productRepository
    ->getList($searchCriteria)
    ->getItems()
    |> array_filter(..., fn($p) => $p->getStatus() === 1)
    |> array_map(..., fn($p) => $p->getSku())
    |> array_values(...)
;

// Zamiast dzisiaj:
$items    = $this->productRepository->getList($searchCriteria)->getItems();
$active   = array_filter($items, fn($p) => $p->getStatus() === 1);
$skus     = array_map(fn($p) => $p->getSku(), $active);
$activeProductSkus = array_values($skus);

Podsumowanie

PHP 8.5 przynosi dwie zmiany które od razu wejdą do kodu: pipe operator eliminuje zagnieżdżone wywołania funkcji i zmienne tymczasowe, readonly class dziedziczenie domyka logikę wprowadzoną w PHP 8.2. Reszta to mniejsze uzupełnienia (array_first/last) i deprecacje przygotowujące do PHP 9.0. Śledzę php-internals przez Feature Freeze – aktualizacja pojawi się po RC1.

About Henryk Tews

Co możesz przeczytać następne

AI workflow 2026 – 2 lata później, co działa, co nie, Claude 200k w praktyce
PHP Enumeracje zaawansowane – backed enums, metody, interfejsy, Magento 2
PHP 8.3 preview – typed constants, json_validate(), array_find(), clone with
  • 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}