1

Asking for decent thoughts about this:

I'd like to implement some mechanism in PHP code that can run any external code and calls a callback function if one of the inclusions fails therein (include, require + *_once).

External code means that the code that is getting executed is not written by me nor is there control over it. It's included for testing. So having detailed info about inclusions failures deeper therein is helpful.

I'm runnning into the problem that it looks impossible to have a callback when a PHP fatal error happens.

What I tried so far:

  • Registering an error handler via set_error_handler - Does not work with fatal errors.
  • Created an object instance with a __destruct() method - Is not invoked with fatal errors.
  • Registered a shutdown function - Is not called on fatal errors.

In any of these I just wanted to fetch a debug_backtrace and then work with the information given.

So question shortly is: how to track failed file inclusions from within PHP code and call a function then.

I fear the answer to the question is no from my recent tries and searches, so anything insightful is highly appreciated. Even if your answer only strengthens the "not possible" point.

Additionally it's helpful as well if it's possible to find out which file is going to be included, so creating a debug output before the inclusion (failing or not) could be done at least.

Remarks:

  • Preferable w/o extensions. However if something exists, I'm eager to know as well.
  • External code means that the code that is getting executed is not written by me nor is there control over it. It's included for testing. So having detailed info about inclusions failures deeper therein is helpful.

Related:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • you can't, because a failed require will always cause a fatal error, and a fatal error will always halt your code. tracking failed includes however would be pretty easy. – dqhendricks Jul 09 '11 at 20:14
  • @dqhendricks: You're making me curious. What do you have in mind to track failed includes? – hakre Jul 10 '11 at 10:05
  • 1
    create a custom error handler that checks the error string for that particular error. – dqhendricks Jul 10 '11 at 19:12
  • @dqhendricks: a custom PHP error handler is not invoked on fatal errors, but you're right, include does not trigger fatal errors. But so wouldn't help with require. – hakre Jul 11 '11 at 10:06
  • perhaps you could write a script that scans the external code files for include/require statements, and checks that the files exist before running them? your script would also have to take into account any include path changes however. – dqhendricks Jul 11 '11 at 15:34

2 Answers2

2

My suggestions are untested, here are some things to try:

If the required/included php files are classes autoload could be an option

function __autoload($class)
{
    // try to load
}

If you can wrap the require/includes in a try catch block setting the error handler to use exceptions might also work: Update: doesn't work :(

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
set_error_handler("exception_error_handler");

If the code you need to test can be tested in the command line using popen and xdebug you execute the program in a separate process if pclose returns -1 you could parse the backtrace from xdebug.

    $cmd = 'php --php-ini path/php.ini file/to/run.php';
    $output = '';
    $popen  = popen($cmd, 'rb');

    while (!feof($popen)) {
        $output .= fread($popen, 4096);
    }

    if (pclose($popen) < 0) {
        // error - parse $output for xdebug backtrace
    }
Glass Robot
  • 2,438
  • 19
  • 11
  • I don't think that hooking into the autoload chain via spl is revealing much info. For non-existant classes it would be called, but that would not reveal which file is going to be included. And the code in question does not explicitly always use autoload, so it would cover only under certain conditions. `set_error_handler`is something I've already tried. Will make that more prominent in the question. – hakre Jul 09 '11 at 16:00
  • If the code or the testing code could be made to run in the command line using popen and xdebug becomes a possible option – Glass Robot Jul 09 '11 at 16:49
  • Thanks for the update. It's indeed on the commandline, the commmand that will get started is PHPUnit. xdebug get's disabled in PHPUnit, however, a bootstrap.php can enable it. Xdebug backtrace is so far what I'm looking into as well as it provides the backtrace on a failed include. It's okay to say that in shell then for the moment, no need to wrap it into fopen. But thanks for the feedback, xdebug is providing the backtrace. – hakre Jul 10 '11 at 10:05
0

You don't need it. To load classes use __autoload function. To include static files use require_once. To load dinamic files you should check them before using (file_exeists, is_readable, etc) and throw exceptions if files not found to take backtrace.

El'
  • 401
  • 7
  • 19