Чому PHP 8 ламає старий код
PHP 8.0 (випущено 2020) та PHP 8.1/8.2 зробили мову більш суворою. Функції, які були «застарілими» (deprecated) у PHP 7.x (тобто ще працювали, але з попередженням), у PHP 8 стали фатальними помилками.
Якщо ваш сайт зламався після оновлення сервера, майже напевно причина в одному з цих пунктів.
Найпоширеніші проблеми
1. Функції mysql_* (видалено в PHP 7, фатальна помилка в PHP 8)
// НЕ ПРАЦЮЄ — повністю видалено
$conn = mysql_connect("localhost", "user", "pass");
$result = mysql_query("SELECT * FROM products");
// ВИПРАВЛЕНО — використовуйте mysqli або PDO
$conn = new mysqli("localhost", "user", "pass", "dbname");
$result = $conn->query("SELECT * FROM products");
Якщо ви досі використовуєте mysql_*, вашому коду щонайменше 10 років. Переписування просте, але трудомістке для великих кодових баз.
2. ereg() та ereg_replace() (видалено в PHP 7)
// НЕ ПРАЦЮЄ
if (ereg("^[a-z]+$", $str)) { ... }
$clean = ereg_replace("[^a-z0-9]", "", $str);
// ВИПРАВЛЕНО — використовуйте еквіваленти preg_
if (preg_match("/^[a-z]+$/", $str)) { ... }
$clean = preg_replace("/[^a-z0-9]/", "", $str);
3. create_function() (видалено в PHP 8.0)
// НЕ ПРАЦЮЄ
$fn = create_function('$x', 'return $x * 2;');
// ВИПРАВЛЕНО — використовуйте анонімну функцію
$fn = function($x) { return $x * 2; };
// або стрілкову функцію
$fn = fn($x) => $x * 2;
4. each() (видалено в PHP 8.0)
// НЕ ПРАЦЮЄ
while (list($key, $val) = each($array)) { ... }
// ВИПРАВЛЕНО
foreach ($array as $key => $val) { ... }
5. Глобальні змінні $HTTP_*_VARS (давно зникли, але ще є в старому коді)
// НЕ ПРАЦЮЄ — ці змінні відсутні з PHP 5.4
$id = $HTTP_GET_VARS['id'];
$name = $HTTP_POST_VARS['name'];
// ВИПРАВЛЕНО
$id = $_GET['id'];
$name = $_POST['name'];
6. Передача null у параметри, що не допускають null (PHP 8.1)
Це підступна проблема, яка ламає чимало сучаснішого коду:
// НЕ ПРАЦЮЄ в PHP 8.1 — strlen не приймає null
$len = strlen(null); // Фатальна помилка: strlen(): Argument #1 must be of type string, null given
// ВИПРАВЛЕНО
$len = strlen($value ?? '');
// або
$len = $value !== null ? strlen($value) : 0;
Це виникає, коли змінні, які можуть бути null, передаються у функції, що очікують рядок або ціле число. Часто зустрічається з результатами бази даних, де стовпець може бути NULL.
7. Арифметичні операції над рядками (PHP 8.0)
// Раніше працювало, тепер TypeError у PHP 8
$total = "10" + "20abc"; // Раніше: 30, тепер: TypeError
// ВИПРАВЛЕНО — явне приведення типів
$total = (int)"10" + (int)"20abc"; // 30
8. ReflectionParameter::getClass() (PHP 8.0)
Код фреймворків часто використовує рефлексію. Цей метод було видалено:
// НЕ ПРАЦЮЄ
$class = $param->getClass();
// ВИПРАВЛЕНО
$type = $param->getType();
if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) {
$class = new ReflectionClass($type->getName());
}
Як знайти всі проблеми одразу
Варіант 1: Перевірка сумісності з PHP
Встановіть php-compatibility за допомогою PHPCS:
composer global require squizlabs/php_codesniffer
composer global require phpcompatibility/php-compatibility
phpcs --standard=PHPCompatibility --runtime-set testVersion 8.0 /path/to/your/code
Це просканує всю вашу кодову базу і перелічить усі проблеми сумісності з файлами та рядками.
Варіант 2: Увімкніть логування помилок спочатку
Якщо ви не можете запустити статичний аналізатор, хоча б увімкніть логування помилок:
// У php.ini або .htaccess
error_reporting = E_ALL
log_errors = On
error_log = /var/log/php_errors.log
display_errors = Off // Не показувати помилки користувачам
Потім запустіть кожну сторінку та перевірте логи. Ви побачите, які саме функції викликають помилки.
Варіант 3: Протестуйте на PHP 8 перед міграцією
Якщо ваш хостинг дозволяє змінювати версію PHP, створіть копію сайту на PHP 8, запустіть її на тиждень і виправте все, що знайдете, перед перемиканням продакшну.
Специфічні проблеми OpenCart з PHP 8
OpenCart 2.x та ранні 3.x мають кілька відомих несумісностей з PHP 8:
| Компонент | Проблема | Виправлення |
|---|---|---|
| Обробка сесій | each() у коді сесій |
Оновлення до OC 3.0.3.8+ |
| Бібліотека зображень | Зміни сигнатури функцій GD | Оновлення або заміна класу зображень |
| Розширення | Багато використовують застарілі функції | Перевірте кожне розширення окремо |
| Модулі оплати | Часто використовують старий стиль mysqli | Замініть або оновіть модуль оплати |
Для OpenCart найшвидший підхід — зазвичай оновитися до останнього патчу 3.x, а потім виправити проблеми розширень по одному.
Коли швидше заплатити комусь
Якщо у вас більше 10–15 файлів з проблемами PHP 8 — і особливо якщо є кастомні розширення чи модифікації — процес аудиту та виправлення може зайняти 3–8 годин на сайт. Спочатку запустіть phpcs, щоб отримати повний список, і тоді приймайте рішення.
Я виконував міграції PHP 8 на всьому — від невеликих сайтів (2 години) до сильно кастомізованих магазинів OpenCart (2 дні). Розкажіть, яка у вас платформа і приблизно скільки кастомних файлів — я дам чесну оцінку.