PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Magento 2.4.9 – oficjalne wsparcie PHP 8.5, co się zmieniło i jak migrować

by Henryk Tews / poniedziałek, 04 maja 2026 / Opublikowano w Magento 2, PHP

Magento 2.4.9 wyszło z oficjalnym wsparciem PHP 8.5. Przez ostatnie miesiące testowałem RC na projektach klientów – teraz jest stable i można planować migracje. Pipe operator, readonly dziedziczenie, nowe array functions – wszystkie PHP 8.5 features są teraz pierwszoklasowymi obywatelami w kodzie modułów Magento. Przeglądam co się faktycznie zmieniło w rdzeniu, co trzeba zaktualizować w własnym kodzie i jak wygląda ścieżka upgrade dla istniejących projektów.

Co nowego w Magento 2.4.9 technicznie

Magento 2.4.9 to nie tylko bumped PHP requirement. Kilka zmian w samym rdzeniu:

Obszar Zmiana Wpływ na developer
PHP support 8.3, 8.4, 8.5 (nowe) Możesz używać pipe operator w modułach oficjalnie
Implicit nullable Naprawione w rdzeniu Brak E_DEPRECATED warnings na PHP 8.5
OpenSearch 2.x i 3.x wspierane Możesz przejść na OS 3.x z vector search
Elasticsearch Usunięte z oficjalnego wsparcia Migruj na OpenSearch jeśli jeszcze nie
MariaDB 10.11 LTS i 11.x MySQL 8.0 nadal wspierany
Composer 2.7+ Sprawdź wersję przed upgrade

Usunięcie Elasticsearch – co zrobić

# Sprawdź aktualny silnik wyszukiwania
bin/magento config:show catalog/search/engine
# Jeśli elasticsearch7 lub elasticsearch8 -> musisz migrować

# Migracja na OpenSearch 2.x (kompatybilna API z Elasticsearch 7)
bin/magento config:set catalog/search/engine opensearch
bin/magento config:set catalog/search/opensearch_server_hostname opensearch
bin/magento config:set catalog/search/opensearch_server_port 9200
bin/magento config:set catalog/search/opensearch_index_prefix magento2

# Reindeksacja po zmianie
bin/magento indexer:reindex catalogsearch_fulltext
bin/magento cache:flush

# Weryfikacja
bin/magento indexer:status catalogsearch_fulltext
# Status: Ready

PHP 8.5 w kodzie modułów – co teraz możliwe oficjalnie

<?php

declare(strict_types=1);

// Od Magento 2.4.9 te wszystkie PHP 8.5 features są oficjalnie OK w modułach

// 1. Pipe operator - liniowe przetwarzanie kolekcji
class OrderExportService
{
    public function getExportableOrders(\DateTimeImmutable $since): array
    {
        return $this->orderRepository->getList($this->buildCriteria($since))->getItems()
            |> array_filter($$, fn($o) => $o->getStatus() !== 'cancelled')
            |> array_filter($$, fn($o) => $o->getGrandTotal() > 0)
            |> array_values($$)
        ;
    }

    private function buildCriteria(\DateTimeImmutable $since): \Magento\Framework\Api\SearchCriteriaInterface
    {
        return $this->searchCriteriaBuilder
            ->addFilter('created_at', $since->format('Y-m-d H:i:s'), 'gteq')
            ->setPageSize(500)
            ->create();
    }
}

// 2. Readonly dziedziczenie - Value Objects dla Magento
readonly class ProductPrice
{
    public function __construct(
        public int $amount,        // w groszach
        public string $currency,
        public int $storeId = 1
    ) {}

    public string $formatted {
        get => number_format($this->amount / 100, 2, ',', ' ') . ' ' . $this->currency;
    }
}

readonly class CustomerSpecificPrice extends ProductPrice
{
    public function __construct(
        int $amount,
        string $currency,
        int $storeId = 1,
        public readonly int $customerGroupId = 0,
        public readonly float $discountPercent = 0.0
    ) {
        parent::__construct($amount, $currency, $storeId);
    }

    public float $originalAmount {
        get => $this->amount / (1 - $this->discountPercent / 100);
    }
}

// 3. array_first / array_last w service methods
class InventoryService
{
    public function getDefaultSource(int $productId): ?SourceInterface
    {
        $sources = $this->sourceRepository->getListByProductSku(
            $this->getSkuById($productId)
        );

        return array_first(array_filter(
            $sources->getItems(),
            fn($s) => $s->getEnabled() && $s->isDefault()
        ));
    }
}

Checklist upgrade do Magento 2.4.9

#!/bin/bash
# Skrypt pre-upgrade check

echo "=== Magento 2.4.9 Pre-upgrade Checklist ==="

# 1. Wersja PHP
PHP_VERSION=$(php -r "echo PHP_VERSION;")
echo "PHP: ${PHP_VERSION}"
# Wymagane: 8.3, 8.4 lub 8.5

# 2. Wersja Composer
COMPOSER_VERSION=$(composer --version | cut -d' ' -f3)
echo "Composer: ${COMPOSER_VERSION}"
# Wymagane: 2.7+

# 3. Silnik wyszukiwania
SEARCH_ENGINE=$(bin/magento config:show catalog/search/engine 2>/dev/null)
echo "Search Engine: ${SEARCH_ENGINE}"
if [[ "$SEARCH_ENGINE" == *"elasticsearch"* ]]; then
    echo "  ⚠ UWAGA: Elasticsearch nie wspierany w 2.4.9 – migruj na OpenSearch!"
fi

# 4. Kompatybilność modułów zewnętrznych
echo ""
echo "Sprawdzanie modułów zewnętrznych na PHP 8.5..."
vendor/bin/phpcs \
    --standard=PHPCompatibility \
    --runtime-set testVersion 8.5 \
    --extensions=php \
    vendor/ 2>/dev/null | grep -c "ERROR" | xargs echo "Błędów kompatybilności PHP 8.5:"

# 5. Sprawdź implicit nullable w własnym kodzie
echo ""
echo "Implicit nullable parameters (napraw przed 2.4.9):"
grep -rn "function.*= null)" app/code/ | grep -v "?.*= null" | grep -v "//.*=" | wc -l | xargs echo "  Znaleziono:"

echo ""
echo "Uruchom na staging: composer require magento/product-community-edition:2.4.9 --no-update && composer update"
# Pełny upgrade process (na staging najpierw!)

# 1. Backup
mysqldump magento_prod | gzip > backup_$(date +%Y%m%d).sql.gz
tar czf code_backup_$(date +%Y%m%d).tar.gz app/code pub/media

# 2. Maintenance mode
bin/magento maintenance:enable

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

composer update

# 4. Magento setup
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy pl_PL en_US -f --jobs=$(nproc)

# 5. Cache i indeksy
bin/magento cache:flush
bin/magento indexer:reindex

# 6. Wyłącz maintenance
bin/magento maintenance:disable

echo "Upgrade zakończony. Sprawdź logi: tail -f var/log/system.log"

Własne moduły – co naprawić przed upgrade

<?php

// Rector automatycznie naprawi najczęstsze problemy
// rector.php - dodaj regułę dla implicit nullable

use Rector\Config\RectorConfig;
use Rector\Php81\Rector\FunctionLike\IntersectionTypesRector;

return RectorConfig::configure()
    ->withPaths(['app/code/'])
    ->withPhpSets(php85: true)
    ->withSets([
        \Rector\Set\ValueObject\SetList::TYPE_DECLARATION,
    ]);

// vendor/bin/rector process app/code/ --dry-run
// vendor/bin/rector process app/code/
# Najczęstsze ręczne poprawki

# Przed:
# public function processOrder(OrderInterface $order, string $note = null): void
# Po:
# public function processOrder(OrderInterface $order, ?string $note = null): void

# Szybkie masowe wyszukiwanie i naprawa przez sed (ostrożnie - sprawdzaj wyniki!)
# grep -rn "= null)" app/code/ --include="*.php" -l | \
#   xargs sed -i 's/\(function [^(]*([^)]*\)\([A-Za-z]\+\) \(\$[a-z]\+ = null\)/\1?\2 \3/g'

# Bezpieczniej: Rector + ręczny code review
vendor/bin/rector process app/code/ --only=\Rector\TypeDeclaration\Rector\Param\ParamTypeFromStrictTypedPropertyRector

Pierwsze wrażenia z projektu na 2.4.9 + PHP 8.5

Pierwszy projekt który przeszedł na 2.4.9 w zeszłym tygodniu – sklep B2B, 45 własnych modułów, 80 zewnętrznych. Czas upgradu na staging: 4 godziny (przede wszystkim kompatybilność 8 modułów zewnętrznych które wymagały aktualizacji vendora). Na produkcji: 45 minut maintenance window.

Po upgrade natychmiast:

  • Zero E_DEPRECATED warnings w logach (byliśmy już na PHP 8.4 – to duże ułatwienie)
  • Czysty PHPStan poziom 8 dla własnego kodu z php-version=8.5
  • Pierwsze własne metody przepisane z pipe operatorem – 3 pliki, kod krótszy i czytelniejszy
  • PageSpeed bez zmian – 2.4.9 to nie Hyvä, frontend Luma jest tym samym Lumą

Podsumowanie

Magento 2.4.9 to upgrade który warto zrobić – głównie ze względu na PHP 8.5 oficjalne wsparcie i pożegnanie Elasticsearch na rzecz OpenSearch. Sam proces upgradu jest rutynowy jeśli jesteś już na PHP 8.4. Największe wyzwanie to zewnętrzne moduły – sprawdź ich kompatybilność zanim zaczniesz. Po stronie kodu własnych modułów: napraw implicit nullable przez Rector i możesz zacząć pisać z pipe operatorem i readonly hierarchiami bez żadnych zastrzeżeń.

About Henryk Tews

Co możesz przeczytać następne

UI Components – siatka danych, DataProvider, własne kolumny, konfiguracja XML
Hyvä zaawansowane wzorce – Alpine.js Store, eventy, lazy loading, reużywalne komponenty
Akeneo PIM – po co PIM, REST API, mapowanie atrybutów, import przez cron
  • 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}