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ń.
