Аннотация
В современной разработке на PHP скрытый BOM (Byte Order Mark) в UTF-8-файлах вызывает фатальные ошибки при использовании конструкций namespace и declare(strict_types=1), требующих быть первыми в скрипте. Появление BOM незаметно происходит при сохранении файлов разными редакторами или автоматических конверсиях, что приводит к труднопойманным сбоям и дополнительным затратам на отладку.
Решения включают ручное удаление BOM в редакторах (Notepad++, VSCode), программные скрипты на PHP и консольные утилиты (sed, awk, iconv), а также комплексный инструмент clean-bom-senior.sh, обеспечивающий рекурсивную очистку, атомарность операций, резервное копирование и интеграцию в CI/CD и прe-commit хуки. Предлагаемые практики настройки IDE, предкоммитные проверки и стандартизация кодировок гарантируют стабильность и предсказуемость работы PHP-приложений.
В PHP объявление пространства имен должно быть самым первым оператором в файле, допускается только предваряющий его declare, а любой вывод до этого (включая BOM) вызывает фатальную ошибку.
В UTF‑8 три байта BOM EFBBBFEFBBBF считаются выводом до открывающего тега, из‑за чего и появляется «Namespace declaration statement has to be the very first statement«
Краткий ответ: ошибка вызвана скрытым BOM в начале файла в кодировке UTF‑8, который выводится до строки namespace и нарушает требование “namespace должен быть первым оператором (кроме declare)”. Сохранить файл как UTF‑8 без BOM и убедиться, что первыми байтами идут символы «<?php» без каких‑либо пробелов/вывода решает проблему

1 · Введение
1.1 Зачем читать это руководство?
BOM-маркеры — невидимые байты EF BB BF — нередко приводят к фатальным ошибкам PHP при использовании конструкций namespace и declare(strict_types=1)[^bom]. Руководство научит:
- обнаруживать и удалять BOM в любых масштабах кода;
- предотвращать повторное появление;
- автоматизировать процесс в IDE, CI/CD и Git-хуках.
1.2 Что нового в 2025?
- clean-bom-senior.sh v2.06.4:
– полное сохранение владельцев, прав, временных меток;
– атомарные операции + резервные копии;
– корректная статистика благодаряwhile ... < <(find);
– глобальный алиасbom. - Расширенные разделы DevOps, Docker, Git Hooks.
2 · Теория BOM и кодировок
2.1 Определение BOM
Byte Order Mark — метка в начале файла, указывающая порядок байтов и кодировку[^glossary-bom].
2.2 Как BOM ломает PHP
PHP требует, чтобы первой инструкцией после <?php были namespace или declare[^php-rule]. Невидимый BOM помещает лишние байты перед ними → Fatal error.
2.3 Чем опасен смешанный CRLF/LF
Windows-редакторы добавляют \r\n. В Unix это воспринимается как «мусорные» символы → диффы «ругаются», тесты CI падают.
3 · Диагностика BOM
| Метод | Однострочный пример | Примечание |
|---|---|---|
| hexdump | `hexdump -C file.php | head -1` |
| od | od -An -tx1 -N3 file.php | Вывод шестнадцатеричных байт |
| file | file -bi file.php | text/php; charset=utf-8 без BOM |
4 · Методы очистки BOM
4.1 Ручные методы
- Notepad++ → Encoding → UTF-8 without BOM
- VS Code → Status Bar → UTF-8 → Save with encoding…
- Sublime Text →
File › Save with Encoding › UTF-8.
4.2 PHP-скрипты
$bom = "\xEF\xBB\xBF";
$txt = file_get_contents($f);
if (strncmp($txt, $bom, 3) === 0) {
file_put_contents($f, substr($txt, 3));
}
4.3 CLI-утилиты
- sed:
sed -i '1s/^\xEF\xBB\xBF//' *.php - awk:
awk 'BEGIN{FS=\"\"}{if(NR==1&&$1==\"\\xEF\")$1=\"\"}1' file.php - iconv:
iconv -f utf-8 -t utf-8 -c file.php -o file.php.
4.4 clean-bom-senior.sh
4.4.1 Установка
curl -Lo /usr/local/bin/bom https://github.com/paulmann/Clean_BOM_Senior/raw/main/clean-bom-senior.sh
chmod +x /usr/local/bin/bom
4.4.2 Запуск
| Команда | Действие |
|---|---|
bom | Рекурсивно чистит всё |
bom --dry-run | Предпросмотр без изменений |
bom --verbose | Подробный лог |
4.4.3 Новые возможности v2.06.4
- Полное сохранение UID/GID, прав, временных меток.
- Statistic Fix — корректные счётчики (исправлен баг pipe).
- Atomic + Backups:
file.bak.PID. - Алиас
bomчерез симлинк:ln -s /home/clean-bom-senior.sh /usr/local/bin/bom.
5 · Интеграция в DevOps
5.1 GitHub Actions
- name: Clean BOM
run: bom --dry-run --verbose
5.2 Git Hooks
Pre-commit проверяет, pre-push чистит автоматически (см. код выше).
5.3 Docker
RUN bom --verbose && rm /usr/local/bin/bom
6 · Предотвращение появления BOM
- Настройка IDE → «UTF-8 without BOM».
- Pre-commit линтеры → отклонять файлы с BOM.
- Стандарты кодирования (PSR-1/12) закрепить в
CONTRIBUTING.md.
7 · Практика и рецепты
7.1 Чистим только PHP и JS
find . -type f \\( -name '*.php' -o -name '*.js' \\) -print0 |
while IFS= read -r -d '' f; do bom \"$f\"; done
7.2 Еженедельный cron
0 3 * * 1 /usr/local/bin/bom --verbose >> /var/log/bom.log 2>&1
8 · Глоссарий
| Термин | Определение |
|---|---|
| BOM | Byte Order Mark — три байта EF BB BF, помечающие UTF-8-файл |
| CRLF | Комбинация символов перевода строки \\r\\n, Windows-стиль |
| Atomic Operation | Изменение файла, гарантирующее целостность (либо всё, либо ничего) |
| Rollback | Автоматическое откатывание изменений при ошибке |
| UID/GID | User ID и Group ID владельца файла |
| CI/CD | Continuous Integration / Continuous Deployment — непрерывная интеграция и доставка |
Ссылки в тексте вида [^bom] ведут на соответствующие термины глоссария.