Вернуться к списку Вернуться к статьям
Статьи

Как мы перевели сайт на 1С-Битрикс с PHP 7.4 на 8.2: разбор легаси-кода и неочевидных ошибок

Как мы перевели сайт на 1С-Битрикс с PHP 7.4 на 8.2: разбор легаси-кода и неочевидных ошибок

Введение: почему переход на PHP 8.2 стал необходимостью для сайта на Битриксе

С февраля 2026 года 1С-Битрикс ограничивает поддержку продуктов на версиях PHP ниже 8.2. Но проблема не только в формальных сроках — PHP 7.4 перестал получать обновления безопасности ещё в ноябре 2022 года. Четыре года без исправлений уязвимостей — это риск, который не можешь игнорировать, если сайт принимает платежи и обрабатывает персональные данные клиентов.

Для servermall — крупного интернет-магазина серверного оборудования на 1С-Битрикс: Управление сайтом — вопрос стоял остро. Сайт существует с 2012 года, за это время накопился внушительный объём самописного кода: кастомные компоненты, обработчики событий, интеграция с AmoCRM, конфигураторы серверов, фильтры — всё в директории /local/. Штатные модули маркетплейса тоже добавили сложности: часть решений не обновлялась годами, у некоторых истекли лицензии, а документация давно не актуальна.

В этой статье — практический разбор перехода: что сломалось при смене версии PHP, какие паттерны ошибок повторялись, как мы их фиксили и что стоит проверить до запуска apt install php8.2.

Контекст проекта

Сайт servermall работает на редакции «1С-Битрикс: Управление сайтом — Бизнес». Каталог из нескольких тысяч товаров, конфигураторы сборки серверов, личный кабинет B2B, интеграция с AmoCRM через кастомный модуль в /local/.

Технический стек на момент начала миграции: PHP 7.4, MySQL 5.7, веб-сервер Apache с nginx-прокси. В директории /local/ около 120 PHP-файлов с бизнес-логикой, написанной в разное время разными разработчиками. Часть кода — наследие эпохи PHP 5.6, которое просто работало на 7.4 за счёт мягкой политики обратной совместимости.

При этом с определённого момента мы ввели правило: весь новый код пишем со строгими типами. Объявления declare(strict_types=1), тайп-хинты на аргументах и возвращаемых значениях, явные приведения вместо надежды на неявное — это вошло в практику задолго до PHP 8. Старый код переписывали постепенно, по мере касания. Такая дисциплина сильно сузила фронт работ при миграции: файлы, написанные по-человечески, переезжали на 8.2 без единого изменения.

Задача на миграцию — №11512 в корпоративном портале, поставлена в октябре 2024 года. Ответственный — Дмитрий Глаголев, основную работу по исправлению кода выполнил Алексей Плотников.

Что изменилось в PHP 8.x: ключевые несовместимости

Переход с 7.4 сразу на 8.2 — это прыжок через две мажорные версии (8.0 и 8.1). Главное изменение — не синтаксис, а философия: PHP перестал прощать нестрогую типизацию. Если на 7.4 можно было передать строку туда, где ожидается число, и интерпретатор молча делал приведение, то 8.2 либо выбрасывает TypeError, либо ведёт себя иначе. Вот что перестало работать из коробки:

  • Обращение к нестатическим методам как к статическим — PHP 8.0 превратил notice в фатальную ошибку. Весь код вида SomeClass::nonStaticMethod() начал падать.
  • Передача не-массива в count() — PHP 8.1 выбрасывает TypeError. Если переменная может быть null или числом — нужна проверка is_countable() или явное приведение к массиву.
  • Передача не-массива в implode() — аналогично: implode(', ', $value) падает, если $value не массив. Приходится оборачивать в проверки.
  • Конструкторы классов — PHP 8.0 убрал поддержку методов с именем класса в качестве конструктора. Старые модули маркетплейса, написанные до 2016 года, использовали этот подход.
  • Short open tags <? — директива short_open_tag по умолчанию выключена в PHP 8. Если в шаблонах или скриптах встречается <? вместо <?php — белый экран.
  • define() без кавычекdefine(CONSTANT_NAME, value) вместо define('CONSTANT_NAME', value). В PHP 7 прокатывало, в 8 — fatal error.
  • Ужесточение типов в выражениях — арифметика с нечисловыми значениями, конкатенация без явного приведения, доступ к индексам не-массивов — всё это либо перестало работать, либо начало выдавать TypeError.

Что сломалось на servermall: разбор по категориям

Мы выкатили PHP 8.2 на тестовую копию сайта и методично фиксили ошибки. Всего потребовалось изменить около 50 PHP-файлов. Все исправления собирались в отдельной ветке, ответвлённой от dev — чтобы не тормозить основные разработки. Разберём по категориям.

1. Нестатические методы, вызываемые статически

Самая частая категория. В файле с обработчиками авторизации метод OnBeforeUserLoginHandler вызывался ядром Битрикса через ExecuteModuleEventEx, но не имел модификатора static. PHP 8.2 падал с ошибкой: «Non-static method cannot be called statically».

Исправление — добавить static:

// Было
function OnBeforeUserLoginHandler(&$arFields) {

// Стало
static function OnBeforeUserLoginHandler(&$arFields) {

Аналогичная ситуация в файле с основными обработчиками — метод setAdWordsTags() класса для рекламных меток вызывался статически, но был объявлен как public function. Добавили static public function.

2. count() и implode() на потенциально не-массивах

В PHP 7.4 код вроде count($curCompare) молча возвращал 0, если $curCompare был null или false. В PHP 8.2 — TypeError. На servermall это проявилось в нескольких шаблонах:

  • Шаблоны шапки и навигации — сравнение товаров ($curCompare) и избранное ($curWishlist). Значения приходили из кук, и при первом заходе были null, а не пустым массивом. Решение: count((array)$curCompare).

  • Модификатор результата в карточке товара — свойство сетевой карты могло быть строкой вместо массива при определённых настройках инфоблока. Решение: проверка is_array() и fallback на пустой массив.

  • Шаблон сравнения товаров — несколько свойств (RAID-контроллер, форм-фактор, сетевая карта, тип подключения, типы дисков и др.) использовались в implode() без проверки типа. Добавили is_array() перед каждым implode().

3. Short open tags

Скрипт, отвечающий за добавление конфигурации сервера в корзину, использовал <? вместо <?php. На PHP 7.4 это работало при short_open_tag = On, в 8.2 — белый экран. Замена заняла 30 секунд, но найти скрипт среди сотен файлов — дольше.

4. define() без кавычек

В файле инициализации константа для reCAPTCHA определялась как define(CONSTANT_NAME, value) — без кавычек вокруг имени. PHP 7.4 интерпретировал имя как строку, PHP 8.2 пытался найти константу с таким именем, не находил и выдавал fatal error. Исправление: define('CONSTANT_NAME', value).

5. Проблемы с высоконагруженными блоками (Highload-блоки)

Модуль интеграции с CRM использовал ORM-таблицу со старым именем. При миграции на PHP 8.2 возникли проблемы с совместимостью — пришлось переименовать таблицу, а функциональность временно закомментирована в подвале сайта с пометкой «TODO: Проблема с базой». Это типичный случай, когда миграция PHP вскрывает архитектурные проблемы, не связанные напрямую с версией языка.

6. Вскрывшиеся баги из-за stricter typing — и почему это хорошо

Одно из главных преимуществ PHP 8 — stricter typing перестаёт прощать ошибки, которые PHP 7 молча глотал. Для кода, написанного без типов, это боль. Для кода, где и так использовались тайп-хинты и строгие проверки — это бесплатная проверка качества.

На servermall мы нашли несколько багов, которые PHP 8.2 подсветил сам:

  • В компоненте списка характеристик переменная с полем сортировки была перепутана с переменной времени кеширования — типичная copy-paste ошибка. На 7.4 она не проявлялась: initCache() проглатывал строку вместо числа и работал с настройками по умолчанию. На 8.2 метод потребовал int — и баг вылез.
  • В шаблоне сравнения товаров свойства передавались в implode() без проверки, что это массив. Для большинства товаров работало, но для некоторых инфоблоков свойство приходило строкой — и implode() молча возвращал эту же строку на 7.4, а на 8.2 начал ронять страницу. Проблема существовала годами, просто никто не замечал.

Главный урок: если вы на 7.4 уже пишете с типами, переход на 8.2 — это не исправление тысяч ошибок, а точечная правка нескольких десятков файлов, где типов не было. В нашем случае из ~120 файлов в /local/ реально сломались около двух десятков — остальные переехали без изменений именно потому, что в них уже были тайп-хинты, declare(strict_types=1) и явные проверки типов.

7. Сторонние модули маркетплейса

Один из сторонних модулей SEO-оптимизации содержал старые конструкторы класса (метод с именем класса вместо __construct()). Это десятки файлов в языковых директориях. К счастью, на момент миграции модуль уже получил обновление, и проблема решилась стандартным обновлением через Marketplace.

Другой сторонний модуль для работы со справочниками — в одном из файлов тоже обнаружились проблемы со статическими вызовами.

Процесс миграции: как мы это делали

Хронология работ:

  1. Отдельная ветка для миграции — ответвили от dev, чтобы не блокировать текущую разработку. Это оказалось палкой о двух концах: пока мы чинили совместимость с PHP 8.2, остальная команда продолжала пушить в dev новые фичи и правки. Приходилось регулярно сливать изменения из dev в миграционную ветку, и почти каждый такой мёрж что-то ломал — то конфликт в шаблонах, то новый код, написанный без оглядки на 8.2. Держать две ветки в синхронизации было едва ли не сложнее, чем сам переход на PHP.

  2. Тестовая копия сайта — полная копия базы и файлов на отдельном окружении с PHP 8.2.

  3. Методичный обход ошибок — включали display_errors = On в файле настроек, открывали страницу за страницей, читали трейс, фиксили, шли дальше. Никакой магии — просто последовательная работа.

  4. Приоритезация — сначала критические ошибки (белый экран на главной и в каталоге), потом предупреждения, потом косметика.

  5. Особое внимание к /local/ — всё, что в этой директории, требует ручной проверки. Штатное ядро Битрикса к тому моменту уже было совместимо с PHP 8.2, а вот самописный код — нет.

  6. Комментирование проблемных участков — когда функциональность нельзя починить быстро (как с AmoCRM), временно отключали с комментарием TODO и номером задачи, чтобы не тормозить весь процесс.

  7. Ревью изменений — каждый починенный файл проверяли на регрессии: не сломала ли правка что-то ещё.

Типичные ошибки при миграции PHP на сайтах под Битриксом

За годы работы с 1С-Битрикс мы накопили список типовых граблей. Вот что чаще всего идёт не так:

Обновление PHP до обновления модулей. Классика: админ просит хостера поднять версию PHP, сайт падает, выясняется что модули маркетплейса не обновлены. Правильный порядок: сначала обновить ядро и все модули на старой версии PHP, потом менять PHP.

Игнорирование сторонних модулей. Модуль с истёкшей лицензией не получает обновлений. При переходе на PHP 8 он может уронить весь сайт. Проверьте статус лицензий до миграции.

Пропуск тестового окружения. Мигрировать на боевом сервере без предварительной проверки — лотерея. Даже если сайт кажется простым, всегда найдётся скрипт, написанный практикантом в 2014 году, который использовал <? и each().

Недооценка объёма легаси в /local/. На servermall самописного кода оказалось больше, чем ожидалось — около 50 файлов потребовали правок. Чем старше сайт, тем больше сюрпризов.

Отсутствие резервной копии. Банально, но перед любым обновлением PHP делайте полный бэкап файлов и базы. Откат на старую версию PHP не всегда помогает, если данные уже повреждены.

Сравнение с альтернативными подходами

Можно было пойти другим путём — не чинить легаси, а переписать сайт с нуля на современном стеке. Для servermall такой вариант не рассматривался: каталог из тысяч товаров со сложной логикой ценообразования, интеграции с AmoCRM, B2B-личный кабинет — переписывать это означало бы остановить развитие на полгода минимум.

Альтернатива «оставить как есть и надеяться» — тоже не вариант. PHP 7.4 не получает исправлений безопасности, а после февраля 2026 года Битрикс перестанет поддерживать такую конфигурацию. Это значит — ни обновлений ядра, ни новых модулей маркетплейса.

Третий путь — переезд на облачный Битрикс24 — решил бы проблему апдейтов PHP, но не подходит для интернет-магазина с глубокой кастомизацией: облачная версия не даёт такого уровня контроля над кодом.

Миграция PHP «на месте» — самый прагматичный путь для зрелых сайтов на 1С-Битрикс с большим объёмом кастомного кода.

Результаты: что дал переход

После завершения миграции:

  • Версия PHP на боевом сервере поднята с 7.4 до 8.2.
  • Все критические ошибки исправлены в 18 файлах, затронувших ключевые сценарии: каталог, корзину, сравнение, избранное, авторизацию и конфигуратор.
  • Производительность выросла незначительно (PHP 8.2 сам по себе быстрее 7.4 на 10-18% по бенчмаркам), но главный результат — сайт снова получает обновления безопасности и совместим с актуальными версиями модулей.
  • Попутно вскрылись и были исправлены несколько багов, годами живших в коде — stricter typing в PHP 8.2 сработал как бесплатный статический анализатор.

Выводы: миграция PHP на сайтах 1С-Битрикс — кому и когда пора обновляться

Переход с PHP 7.4 на 8.2 на сайте под 1С-Битрикс — задача трудоёмкая, но решаемая. Главный вывод: основной объём проблем возникает не в ядре Битрикса (оно к 2025 году уже полностью совместимо с PHP 8.x), а в самописном коде и старых модулях маркетплейса.

Если ваш сайт работает на Битриксе и до сих пор на PHP 7.4 — не откладывайте миграцию. С февраля 2026 года вы не сможете устанавливать обновления. Начните с аудита директории /local/ — посчитайте количество PHP-файлов, оцените возраст кода по коммитам, проверьте лицензии сторонних модулей. Затем поднимите тестовую копию на PHP 8.2 и методично пройдите по ошибкам. За неделю-две можно полностью завершить миграцию даже для крупного проекта.

Проект servermall после перехода стабильно работает на PHP 8.2 — сайт принимает заказы, конфигуратор собирает серверы, личный кабинет обслуживает B2B-клиентов. А самое приятное — apt upgrade снова делает только то, что должен: обновляет пакеты, а не ломает сайт.