PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Magento 2.4.9 – official PHP 8.5 support, what changed and how to migrate

by Henryk Tews / Monday, 04 May 2026 / Published in Magento 2, PHP

Magento 2.4.9 was released in May 2025 alongside official PHP 8.5 support. This is the first Magento release where PHP 8.5’s pipe operator is available out of the box. Beyond PHP 8.5, the release brings performance improvements, updated dependencies, and deprecation cleanup. I show what actually changed, how to migrate, and which PHP 8.5 features are worth using in modules immediately.

What’s new in Magento 2.4.9

Area Change Impact
PHP support PHP 8.5 fully supported, PHP 8.2 dropped High – upgrade PHP runtime
MariaDB 10.11+ recommended (10.6 still supported) Low-Medium
OpenSearch OpenSearch 2.x supported, 3.x experimental Low
Performance Improved DI compilation, faster cache operations Medium
GraphQL Additional batch resolvers in core Low for most
Hyvä Not part of Magento core, but 2.4.9 tested and compatible Low
Security CSP improvements, updated JWT handling Medium

PHP 8.5 features to use immediately in modules

<?php

declare(strict_types=1);

// 1. PIPE OPERATOR - most impactful for collection processing
class ProductExportService
{
    public function getExportData(int $storeId): array
    {
        $sc = $this->searchCriteriaBuilder
            ->addFilter('status', 1)
            ->setPageSize(1000)
            ->create();

        return $this->productRepository->getList($sc)->getItems()
            |> array_filter(..., fn($p) => (float)$p->getPrice() > 0)
            |> array_map(..., fn($p) => $this->toExportRow($p, $storeId))
            |> array_values(...);
    }
}

// 2. array_first() and array_last() - replace clunky idioms
class OrderProcessor
{
    public function getLatestPendingOrder(int $customerId): ?OrderInterface
    {
        $orders = $this->getOrdersByCustomer($customerId);
        return array_first(
            $orders,
            fn($o) => $o->getStatus() === 'pending'
        );
    }

    public function getMostRecentOrder(int $customerId): ?OrderInterface
    {
        return array_last($this->getOrdersByCustomer($customerId));
    }
}

// 3. Readonly property inheritance - cleaner event hierarchies
readonly class MagentoEvent
{
    public function __construct(
        public int $storeId,
        public \DateTimeImmutable $occurredAt,
    ) {}
}

readonly class ProductSavedEvent extends MagentoEvent
{
    public function __construct(
        int $storeId,
        \DateTimeImmutable $occurredAt,
        public int $productId,
        public string $sku,
    ) {
        parent::__construct($storeId, $occurredAt);
    }
}

Migration checklist: Magento 2.4.8 to 2.4.9

#!/bin/bash
# migration-check.sh

echo "=== Magento 2.4.9 migration pre-check ==="

# 1. Check PHP compatibility
echo "PHP compatibility check..."
vendor/bin/phpcs app/code/ --standard=PHPCompatibility \
    --runtime-set testVersion 8.5 --report=summary

# 2. PHPStan with PHP 8.5 baseline
echo "PHPStan PHP 8.5 check..."
vendor/bin/phpstan analyse app/code/ --php-version=8.5 --level=5 \
    --error-format=table | tail -20

# 3. Check for removed functions
echo "Checking deprecated function usage..."
grep -rn "utf8_encode\|utf8_decode\|money_format\|each(" app/code/ --include="*.php" | head -20

# 4. Check implicit nullable parameters
grep -rn "function.*string \$[a-z]* = null\|function.*int \$[a-z]* = null\|function.*float \$[a-z]* = null" \
    app/code/ --include="*.php" | grep -v "?string\|?int\|?float" | head -20

# 5. Run existing tests
echo "Running test suite..."
vendor/bin/phpunit app/code/ --testsuite=Unit 2>&1 | tail -20

echo "=== Checks complete ==="
# Full upgrade process
# On staging environment first!

# 1. Backup
mysqldump -u magento -p magento > backup_before_249.sql

# 2. Enable maintenance
bin/magento maintenance:enable

# 3. Update Magento
composer require magento/product-community-edition:2.4.9 \
    --no-update --no-interaction
composer update --no-interaction

# 4. Upgrade PHP runtime to 8.5 (if not already done)
# In DDEV:
# ddev config --php-version=8.5
# ddev restart

# 5. Run setup
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy pl_PL en_US -f

# 6. Cache flush and disable maintenance
bin/magento cache:flush
bin/magento maintenance:disable

# 7. Run smoke tests
curl -sI https://shop.ddev.site/ | head -5
curl -sI https://shop.ddev.site/admin/ | head -5
bin/magento indexer:status

PHP 8.5 pipe operator in Magento codebase – style guide

<?php

declare(strict_types=1);

// When to use pipe operator in Magento modules:

// YES - sequential data transformations
$processedItems = $quote->getItems()
    |> array_filter(..., fn($i) => !$i->isDeleted())
    |> array_map(..., fn($i) => $this->mapToDto($i))
    |> array_values(...);

// YES - string normalisation
$slug = $product->getName()
    |> trim(...)
    |> strtolower(...)
    |> fn($s) => preg_replace('/[^a-z0-9\s-]/', '', $s)
    |> fn($s) => preg_replace('/\s+/', '-', $s);

// NO - side effects or mutations (use regular code)
// array_walk has side effects - do not use in pipe
// foreach loops - do not use in pipe

// NO - when the chain is two steps or fewer
// $result = trim(strtolower($name)); // fine as nested
// $result = $name |> strtolower(...) |> trim(...); // unnecessary for 2 steps

// Style: align |> operators for readability
$result = $orders
    |> array_filter(..., fn($o) => $o->getStatus() === 'complete')
    |> array_map(...,   fn($o) => $o->getGrandTotal())
    |> array_sum(...);

Summary

Magento 2.4.9 + PHP 8.5 is the current recommended stack for new projects. The upgrade from 2.4.8 is smooth – no major architectural changes, mostly dependency updates and deprecation cleanup. PHP 8.5’s pipe operator is immediately useful in module code for collection transformations. The migration checklist catches the common issues before they become problems in production. For existing projects on 2.4.8 with PHP 8.4 – no rush, both are supported until 2027. For new projects – start on 2.4.9 with PHP 8.5.

About Henryk Tews

What you can read next

Xdebug – configuration, PHPStorm, debugging Magento plugins
Strategy pattern in PHP – and how Magento 2 uses it in pricing
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}