Call to undefined function - причины по убыванию частоты
Страница или скрипт падает с сообщением о неизвестной функции либо методе. Разбираем причины в порядке убывания частоты.
Как проверить
Читаем сообщение целиком:
grep -i "call to undefined" /var/log/php-fpm/error.log | tail -5tail -30 $DOCROOT/bitrix/modules/error.log # журнал платформы, если он включён# журнал платформы включают в .settings.php, в разделе обработки исключенийСообщение всегда называет три вещи: имя функции, файл и строку вызова. С них и начинают, потому что дальше всё сводится к вопросу, чья это функция и почему её не оказалось на месте.
Выясняем, чья это функция:
grep -rn "function ИМЯ_ФУНКЦИИ" bitrix/modules/ local/ | head -3php -m | grep -iE 'mbstring|curl|gd|mysqli|zip' # расширения PHP на месте?# консольный PHP и PHP веб-сервера бывают разными сборками с разным наборомФункция бывает четырёх видов: ядро платформы, модуль продукта, расширение языка и свой код проекта. Поиск по каталогам модулей и по своему коду отвечает на этот вопрос за минуту.
Проверяем подключение модуля перед вызовом:
if (!\Bitrix\Main\Loader::includeModule('sale')) { throw new \RuntimeException('модуль продаж не установлен или отключён');}// без этой строки классов и функций модуля в скрипте просто нет// проверять результат обязательно: в младших редакциях модуля может не бытьМодуль подключают там же, где им пользуются, а не один раз на весь проект. Обработчик события, консольный скрипт и своя страница в админке - три разных входа, и каждому нужна своя проверка.
Запускаем свой скрипт с прологом:
$_SERVER['DOCUMENT_ROOT'] = realpath(__DIR__ . '/../..');define('NO_KEEP_STATISTIC', true);define('NOT_CHECK_PERMISSIONS', true);require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';// без пролога доступен только чистый PHP: ни ядра, ни автозагрузки классовПролог поднимает ядро, автозагрузку и соединение с базой. Файл, запущенный напрямую, о платформе не знает ничего, и первая же функция ядра в нём падает с этим самым сообщением.
Проверяем автозагрузку своего класса:
var_dump(class_exists(\Vendor\Shop\Helper::class)); // класс виден автозагрузке?\Bitrix\Main\Loader::registerAutoLoadClasses('vendor.shop', [ '\\Vendor\\Shop\\Helper' => 'lib/helper.php', // путь считается от папки модуля]);// имя файла и регистр букв обязаны совпадать с записью автозагрузкиСвой класс находится не сам по себе, а по правилу автозагрузки. Регистр букв в имени файла на боевом сервере значит больше, чем на стенде: там файловая система обычно к регистру безразлична, и ошибка проявляется только после выкладки.
Причины
-
Модуль не подключён перед вызовом примерно 30% случаев
ПризнакИмя функции или класса принадлежит модулю: продажи, каталог, инфоблоки.
ПроверкаСмотрим начало файла: есть ли подключение модуля до первого обращения к нему.
Что делатьПодключаем модуль и проверяем результат подключения, а не полагаемся на то, что его подключил кто-то раньше.
-
Скрипт запущен без пролога платформы примерно 25% случаев
ПризнакОшибка возникает в задании по расписанию или в своём файле, запускаемом напрямую.
ПроверкаПроверяем, подключается ли пролог ядра и задан ли корень сайта до его подключения.
Что делатьПодключаем пролог в начале скрипта: без него нет ни функций старого ядра, ни автозагрузки классов.
-
Расширение PHP отсутствует или отключено примерно 20% случаев
ПризнакИмя функции начинается с известной приставки расширения: работа со строками, запросы, картинки.
ПроверкаСмотрим список загруженных расширений и сравниваем его со списком требований платформы.
Что делатьДоставляем пакет расширения и перезапускаем службу процессов PHP; после смены версии список расширений собирают заново.
-
Функция удалена в новой версии языка примерно 15% случаев
ПризнакОшибка появилась ровно после перехода на новую версию PHP, до этого код работал годами.
ПроверкаИщем вызов в своём коде и сверяем функцию со списком удалённого в этой версии языка.
Что делатьПереписываем вызов на действующий аналог, а в чужом решении обновляем его до совместимой версии.
-
Свой класс или файл не загрузился примерно 10% случаев
ПризнакНе найден метод или функция собственного кода проекта, а файл при этом на месте.
ПроверкаСверяем имя класса с путём файла и проверяем, регистрируется ли автозагрузка своего модуля.
Что делатьПриводим имя файла к имени класса либо подключаем файл явно; в админке файл сайта не подключается вовсе.
Если ничего не помогло
Смотрим трассировку целиком, а не одну верхнюю строку. Она показывает, кто вызвал упавший код, и часто виновником оказывается стороннее решение, а не тот файл, который назван в сообщении.
Проверяем, доехал ли файл до боевого сайта. Половина необъяснимых случаев - это выкладка, при которой один файл остался старым, а второй уже новый и вызывает несуществующий метод.
Сбрасываем кэш байт-кода после выкладки. Устаревший скомпилированный файл переживает замену исходника, и тогда ошибка указывает на строку, которой в файле давно нет.
Частые вопросы
Функция есть в документации, но на сайте её нет - почему?
Модуль, которому она принадлежит, не установлен в этой редакции или не подключён в текущем скрипте. Проверяют оба условия: наличие модуля в списке установленных и его подключение перед вызовом.
Что нужно скрипту по расписанию, чтобы функции ядра работали?
Подключение пролога платформы и заданный корень сайта до него. Без пролога доступен только чистый PHP: ни функций старого ядра, ни автозагрузки классов в таком скрипте нет.
Ошибка появилась сразу после перехода на новый PHP.
Либо пропало расширение языка, либо функция удалена в этой версии. Список загруженных расширений и список удалённых функций закрывают оба варианта за пару минут.
Сообщение говорит про метод, а не про функцию.
Класс найден, а метода в нём нет: обычно это код, написанный под другую версию продукта или модуля. Смотрят версию модуля и историю изменений его класса.
Как быстро понять, чья это функция?
Поиском по каталогу модулей и по своему коду, а затем по списку расширений языка. Три этих места покрывают почти все случаи, а четвёртое - стороннее решение из Маркетплейса.
Смежное
- Class not found: причины по убыванию частоты - та же ошибка, но про класс, а не функцию
- Ошибки сервера - оглавление подтемы
- Ошибки 500 и 502: где искать причину и чем они отличаются - что делать с белым экраном
- Ошибка после обновления PHP: причины по убыванию частоты - соседний разбор про смену версии
- Свой модуль: структура, установка, автозагрузка - как настраивается автозагрузка своего кода
- Call to a member function on null: причины по убыванию частоты - соседняя ошибка про пустой объект
- Инфраструктура - устройство сервера и окружения