PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP 8.5 RFCs – pipe operator, readonly inheritance, why generics are not coming yet

by Henryk Tews / Tuesday, 04 February 2025 / Published in PHP

PHP 8.5 RFCs are actively being discussed on the php.net internals list. The pipe operator proposal has been debated for years and may finally ship. Readonly property inheritance fixes an inconsistency. Generics are discussed but will not come in 8.5. I look at the most impactful proposals, show what the code would look like, and explain why generics remain out of reach in the short term.

Pipe operator – |>

<?php

declare(strict_types=1);

// Without pipe operator - nested calls, read right-to-left
$result = array_sum(
    array_map(
        fn($p) => $p['price'],
        array_filter($products, fn($p) => $p['status'] === 1)
    )
);

// With pipe operator - left-to-right, readable as a pipeline
$result = $products
    |> array_filter(?, fn($p) => $p['status'] === 1)
    |> array_map(fn($p) => $p['price'], ?)
    |> array_sum(?);

// The ? placeholder is where the piped value goes
// If no ?, the value is passed as the first argument

// More examples:
$slug = $productName
    |> strtolower(?)
    |> trim(?)
    |> preg_replace('/[^a-z0-9]+/', '-', ?)
    |> trim(?, '-');

// Chain with methods
$total = $order
    |> $this->applyDiscount(?, $discountCode)
    |> $this->calculateTax(?)
    |> $this->addShipping(?, $shippingMethod);

Readonly property cloning – clean “with” pattern

<?php

declare(strict_types=1);

// PHP 8.4 - workaround for creating modified copies of readonly objects
readonly class Money
{
    public function __construct(
        public int $amount,
        public string $currency,
    ) {}

    // Have to create a new instance manually - verbose
    public function withAmount(int $amount): static
    {
        return new static($amount, $this->currency);
    }
}

// PHP 8.5 proposal: clone with syntax
readonly class Money
{
    public function __construct(
        public int $amount,
        public string $currency,
    ) {}

    public function withAmount(int $amount): static
    {
        // Clone this object but override specific properties
        return clone($this, amount: $amount);
    }
}

$price    = new Money(9999, 'PLN');
$discount = clone($price, amount: 7999); // 79.99 PLN
// Original unchanged: $price->amount === 9999

Why generics are not coming in PHP 8.5

<?php

// What generics would look like (RFC level thinking):
class TypedCollection<T>
{
    private array $items = [];

    public function add(T $item): void { $this->items[] = $item; }
    public function get(int $index): T { return $this->items[$index]; }
    /** @return T[] */
    public function all(): array { return $this->items; }
}

$products = new TypedCollection<ProductInterface>();
$products->add(new SimpleProduct()); // OK
$products->add("not a product");     // TypeError at runtime

// Why it is hard:
// 1. PHP's type system is runtime-checked, not compile-time
//    Generics need either runtime enforcement (expensive) or erasure (no runtime checking)
// 2. Type erasure (like Java) means TypedCollection<Product> and TypedCollection<string>
//    are the same class at runtime - no instanceof check possible
// 3. Reified generics (like C#) require generating separate classes for each type parameter
//    - massive memory and performance overhead
// 4. Template-based (like C++) requires compilation step PHP doesn't have

// Current solution: PHPStan generics via docblocks (zero runtime cost)
/** @template T of ProductInterface */
class TypedCollection
{
    /** @var T[] */
    private array $items = [];

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

    /** @return T */
    public function get(int $index): mixed { return $this->items[$index]; }
}

/** @var TypedCollection<SimpleProduct> $products */
$products = new TypedCollection();
// PHPStan enforces T = SimpleProduct at analysis time, zero runtime cost

Other PHP 8.5 proposals

<?php

// 1. array_zip() - transpose multiple arrays
// Before
$names  = ['Alice', 'Bob', 'Carol'];
$emails = ['a@a.com', 'b@b.com', 'c@c.com'];
$pairs  = array_map(null, $names, $emails); // [[Alice, a@a.com], [Bob, b@b.com], ...]

// PHP 8.5 proposal
$pairs = array_zip($names, $emails);

// 2. mb_str_split() improvements
// Already exists in PHP 7.4, may get additional options

// 3. Deprecate implicit nullable parameters (enforce what 8.4 started)
// function foo(string $x = null) -> must become function foo(?string $x = null)

// 4. throw expression in more contexts
// Already works in PHP 8.0, 8.5 may extend further

// 5. Scope resolution in more contexts
$class = SomeClass::class;
$result = $class::create(); // Currently requires extra step
// May allow: SomeClass::class::create() or similar

Following PHP development

# Stay current with PHP development:

# 1. php.net/rfc - all RFC proposals, votes, and discussions
# 2. Externals.io - web interface for the php internals mailing list
# 3. PHP Weekly newsletter (phpweekly.com)
# 4. Brent Roose's blog (stitcher.io) - clear summaries of PHP changes
# 5. GitHub: php/php-src - see actual implementation PRs

# Watch these RFC discussions in 2025:
# - Pipe operator: https://wiki.php.net/rfc/pipe-operator-v3
# - Clone with syntax: https://wiki.php.net/rfc/clone_with
# - Generics (informational): https://externals.io/search?q=generics

Summary

PHP 8.5 is shaping up as a developer ergonomics release. The pipe operator, if it passes the vote, will change how functional-style data transformations are written. Clone-with is a small but meaningful quality-of-life improvement for immutable value objects. Generics remain the most requested feature that will not come soon – PHPStan’s @template approach provides the analysis benefits without the runtime complexity that native generics would require.

About Henryk Tews

What you can read next

PHP 7.2 – object type hint, sodium instead of mcrypt, deprecations

© 2026 Created by

TOP
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 Always active
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.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}