Папка /local в 1C-Битрикс: структура проекта без боли и костылей
Практический разбор папки /local в 1C-Битрикс: правильная структура php_interface, init.php, components, templates и modules по документации. Как не ломать обновления ядра и упростить поддержку.
Требования
- Опыт разработки под 1C-Битрикс
- Понимание структуры проекта и php_interface
- Поддержка или доработка существующего сайта
Папка /local в 1C-Битрикс: как разложить проект по полочкам и не страдать при доработках
Открывал чужой init.php и видел там сотни строк хелперов, SQL и обработчиков вперемешку — знакомо. Разобраться, где что лежит и что можно трогать при обновлении ядра, бывает муторно. Ниже — только практика по папке /local: как в документации Bitrix и как лучше организовать код, чтобы обновления не ломали кастом.
Разберём структуру по шагам, с путями и примерами кода.

Зачем вообще нужна /local
В документации Bitrix чётко разделяют:
- /bitrix — ядро продукта, его не правим.
- /local — весь наш код: компоненты, шаблоны, обработчики, свои модули.
При обновлении продукта каталог /bitrix перезаписывается. Всё, что лежит там «для удобства», однажды может быть затерто или сломано. Всё кастомное имеет смысл держать в /local: он обновлениями не затрагивается.
Кратко: не трогаем /bitrix — работаем в /local.
Базовая структура /local: как в документации и как в жизни
Минимально система ожидает под /local хотя бы точку входа в свой PHP:
/local
├── php_interface
│ ├── init.php
│ └── dbconn.php // опционально, если выносим настройки подключения к БД
Файл /local/php_interface/init.php подключается на каждом запросе — это единая точка входа в пользовательский PHP. От того, как он устроен, зависит, превратится ли проект в поддерживаемый или в «свалку».

/local/php_interface: как не превратить init.php в свалку
❌ Плохо (типичный legacy)
В одном файле — и обработчики, и хелперы, и куски логики:
<?php
// init.php — тысячи строк
AddEventHandler('main', 'OnProlog', function() { ... });
AddEventHandler('sale', 'OnOrderSave', 'myOrderHandler');
function formatPrice($price) { return number_format($price, 0, '', ' '); }
function getCatalogIblockId() { return 12; }
// ещё десятки функций и SQL-запросы...
Такой файл тяжело читать, тестировать и безопасно менять при обновлениях.

✅ Правильно: init.php только подключает файлы
По рекомендациям Bitrix, в init.php имеет смысл оставить только подключение отдельных файлов. Вся логика — в классах и отдельных модулях.
Рекомендуемая структура
/local/php_interface
├── init.php
├── events.php // регистрация обработчиков событий
├── constants.php // константы проекта
├── autoload.php // автозагрузка классов из /local/php_interface/lib
└── lib/
├── Helpers/
├── Services/
└── Repositories/
Пример init.php
<?php
// /local/php_interface/init.php
require_once __DIR__ . '/constants.php';
require_once __DIR__ . '/autoload.php';
require_once __DIR__ . '/events.php';
Коротко и предсказуемо: при доработках правим отдельные файлы, а не гигантский init.php.
constants.php — константы в одном месте
Вынос ID инфоблоков, флагов окружения и прочего в константы избавляет от «магических чисел» по коду:
<?php
// /local/php_interface/constants.php
define('PROJECT_ENV', 'production');
define('CATALOG_IBLOCK_ID', 12);
define('NEWS_IBLOCK_ID', 3);
define('PARTNERS_IBLOCK_ID', 8);
В компонентах и сервисах используем CATALOG_IBLOCK_ID, а не голую двенадцать — так проще искать и менять при переносе на другой сайт.
autoload.php — автозагрузка своего кода
Bitrix поддерживает регистрацию автозагрузки классов из /local/php_interface/lib через Loader::registerAutoLoadClasses. Это не Composer, но стабильно работает в любой типовой установке.
Пример регистрации сервиса и хелпера:
<?php
// /local/php_interface/autoload.php
use Bitrix\Main\Loader;
Loader::registerAutoLoadClasses(null, [
'Project\\Services\\OrderService' =>
'/local/php_interface/lib/Services/OrderService.php',
'Project\\Helpers\\Catalog' =>
'/local/php_interface/lib/Helpers/Catalog.php',
]);
Пример самого класса (логика не в init.php, а в сервисе):
<?php
// /local/php_interface/lib/Services/OrderService.php
namespace Project\Services;
use Bitrix\Main\Loader;
class OrderService
{
public static function onOrderSaved(\Bitrix\Main\Event $event): void
{
$order = $event->getParameter('ENTITY');
if (!$order) {
return;
}
// Отправка в CRM, обновление склада и т.д.
// Всё здесь, а не в events.php
}
}
events.php — только регистрация событий
В этом файле — исключительно привязка событий к классам или функциям. Бизнес-логика остаётся в классах.
<?php
// /local/php_interface/events.php
use Bitrix\Main\EventManager;
$eventManager = EventManager::getInstance();
$eventManager->addEventHandler(
'sale',
'OnSaleOrderSaved',
['Project\\Services\\OrderService', 'onOrderSaved']
);
$eventManager->addEventHandler(
'iblock',
'OnAfterIBlockElementAdd',
['Project\\Services\\CatalogService', 'onElementAdd']
);
Так проще искать обработчик по имени модуля и события и не размазывать логику по init.php.
/local/components: свои компоненты без боли
Компоненты система ищет сначала в /local/components, затем в /bitrix/components. Свои и доработанные компоненты логично держать в /local:
/local/components/ваш_неймспейс/имя.компонента/
Пример: кастомный вывод раздела каталога:
/local/components/my/catalog.section.custom/
├── component.php
├── .description.php
├── templates/
│ └── .default/
│ ├── template.php
│ └── result_modifier.php
Миграция с legacy-проекта
Если компонент до сих пор лежит в /bitrix/components:
- Копируем папку целиком в
/local/components(тот же неймспейс и имя). - Проверяем работу сайта (кеш при необходимости сбрасываем).
- Только после этого удаляем копию из
/bitrix/components.
Шаблоны компонентов тоже лучше хранить в /local/templates, а не править штатные в /bitrix/templates.
/local/templates: свои шаблоны сайта
Типовая структура:
/local/templates
├── main/
│ ├── header.php
│ ├── footer.php
│ ├── description.php
│ └── components/
Всё, что правим в шаблоне сайта, делаем в копии под /local/templates. Правки в /bitrix/templates при обновлении могут быть перезаписаны.
/local/modules: когда проект дорос
Если появляется своя логика (общие сервисы, интеграции, сложная бизнес-логика), удобно вынести её в отдельный модуль под /local/modules:
/local/modules/project.core/
├── install/
│ └── index.php
├── lib/
│ └── SomeService.php
└── include.php
Плюсы: автозагрузка через ядро, изоляция по namespace, проще сопровождать и подключать только там, где нужно. Минус — нужно один раз настроить структуру и установку; на долгой дистанции это обычно окупается.
/local/tools: скрипты и утилиты
В /local/tools обычно кладут разовые или фоновые скрипты: импорт, синхронизация, выгрузки. Не API и не основная бизнес-логика — именно утилиты.
/local/tools
├── import.php
├── sync_catalog.php
Вызов — по необходимости (cron, ручной запуск), без смешивания с основным кодом сайта.
Миграция с legacy: как не уронить прод
- Компоненты: копируем из
/bitrix/componentsв/local/components, проверяем, затем удаляем из/bitrix. - init.php: сначала выносим функции в отдельные файлы и подключаем через
require_once, затем по мере возможности переносим логику в классы и подключаем черезautoload.phpиevents.php. Рефакторим по шагам, а не «всё сразу».
Так снижаем риск поломки продакшена при наведении порядка.
Чек-лист здорового /local
Имеет смысл стремиться к тому, чтобы:
- В
init.phpбыло не больше 10–20 строк (только подключения). - Регистрация событий — в
events.php. - Бизнес-логика — в классах под
/local/php_interface/libили в своём модуле. - Свои компоненты — только в
/local/components. - Шаблоны — только в
/local/templates. - В
/bitrixничего не правим.
Типичные анти-паттерны (и как исправить)
| Проблема | Что сделать |
|---|---|
Всё в init.php | Вынести в lib/, подключить через autoload.php и events.php. |
Компоненты в /bitrix/components | Перенести в /local/components и проверить работу. |
Правки шаблонов в /bitrix/templates | Сделать копию в /local/templates и править её. |
Мини-кейс из практики
Реальный проект на 1C-Битрикс, сайт жил уже несколько лет. В /local/php_interface/init.php накопилось под две тысячи строк: десятки AddEventHandler (каталог, заказы, инфоблоки), функции-хелперы для цен и вывода элементов, куски CIBlockElement::GetList и опросов к БД — всё в одном файле. При обновлении ядра страшно было трогать что угодно; новый разработчик тратил недели, чтобы найти, где вешается обработчик и куда дописать логику. Сделали по рекомендациям из документации: вынесли константы в constants.php, регистрацию событий — в events.php, классы — в /local/php_interface/lib с автозагрузкой через Loader::registerAutoLoadClasses. Кастомные компоненты перенесли из /bitrix/components в /local/components. В итоге init.php — около десятка строк подключений, логика в сервисах и обработчиках. Онбординг новых людей и доработки по заявкам заметно ускорились, обновления продукта перестали вызывать панику.
Итог
Папка /local в 1C-Битрикс — не формальность, а способ держать кастомный код отдельно от ядра и спокойно обновляться. Стоит воспринимать её как основное место для своего кода: проектировать структуру осознанно, не превращая init.php в свалку и не размазывая правки по /bitrix.
/bitrix не трогаем — всё своё ведём в /local.



Комментарии