require_once on a missing file fatals the page

Introduction

A renamed helper file plus a lagging deploy took down every page that rendered our analytics counter. The cause was one line: a bare require_once on a file the server did not have yet. This page shows the failure and the guard pattern that makes optional modules safe.

Author: Arthur Isaev

Why missing require_once kills the page

Unlike a missing function call (catchable Error), a failed require_once is fatal at compile time of that statement: nothing after it runs — no fallback, no counter, no page. In our case the counter class moved from Metrika.php to Metrica.php while hosting still served the old name, so Page::metrika() died on every article. Where the require sat at the top of the file, the entire section went down with it.

$ php -r 'require "/srv/www/.php/_modules/Metrica.php";'

PHP Warning: require(...): Failed opening required ...
PHP Fatal error: Uncaught Error: Failed opening required ...

Guard: is_file before require

Check first, require second. A missing module then skips instead of killing the request:

<?php $mod = $_SERVER['DOCUMENT_ROOT'] . '/.php/_modules/Metrica.php'; if (is_file($mod)) { require_once $mod; return (new \Aredel\Php\Modules\Metrica())->aredel(); } // ... fall through to the baked-in default below

Fallback chain and single shared copy

Order of preference: shared module file, then a baked-in default snippet (byte-identical to the module output, so visitors see no difference). Three copies of the module became one — every extra copy is another file a partial deploy can miss, which is exactly the failure we started from. Stale pre-rename files left on the server are listed for removal; afterwards the fallback only ever fires on genuinely missing modules.

Full incident record (commit plan 10 timeline, file inventory): PHP errors: case studies.

Автор статьи: Андрей Олегович