Stop script execution upon notice/warning

Is it possible to have PHP stop execution upon a notice/warning, globally?

We run a development server with a lot of sites on, but want to force our developers to fix these warnings/notices (or ask for help with them at least) instead of ignoring and moving on.


Solution 1:

Yes, it is possible. This question speaks to the more general issue of how to handle errors in PHP. You should define and register a custom error handler using set_error_handlerdocs to customize handling for PHP errors.

IMHO it's best to throw an exception on any PHP error and use try/catch blocks to control program flow, but opinions differ on this point.

To accomplish the OP's stated goal you might do something like:

function errHandle($errNo, $errStr, $errFile, $errLine) {
    $msg = "$errStr in $errFile on line $errLine";
    if ($errNo == E_NOTICE || $errNo == E_WARNING) {
        throw new ErrorException($msg, $errNo);
    } else {
        echo $msg;
    }
}

set_error_handler('errHandle');

The above code will throw an ErrorException any time an E_NOTICE or E_WARNING is raised, effectively terminating script output (if the exception isn't caught). Throwing exceptions on PHP errors is best combined with a parallel exception handling strategy (set_exception_handler) to gracefully terminate in production environments.

Note that the above example will not respect the @ error suppression operator. If this is important to you, simply add a check with the error_reporting() function as demonstrated here:

function errHandle($errNo, $errStr, $errFile, $errLine) {
    if (error_reporting() == 0) {
        // @ suppression used, don't worry about it
        return;
    }
    // handle error here
}

Solution 2:

You can globally configure this within your php.ini file­Docs.

It can be done by specifying a file that is being included by all PHP processes with the auto_prepend_file directive­Docs:

auto_prepend_file "/full/path/to/a/prepend-file.php"

Doing that inside your global php.ini file will ensure that the code inside the prepend file will be always executed. Use it then to register a global error handler that will turn all errors into exceptions­Docs:

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

This little script will turn all errors/warnings/notices etc. into an ErrorException.

This code example is likely too short (will comment further below) so don't miss the examples on the set_error_handler()­Docs manual page.

Combine it with the error_reporting ini directive­Docs, the values are describe in your php.ini file (or as another option use the second parameter for set_error_handler handle errors by their severity).

Throwing an exception is a very strict thing. Your programmers will be forced to deal with warnings and errors otherwise the code won't not work (including those in code with the @ error control operator, rendering it void).

Probably this is too much and not socially acceptable within the company. Instead you can also log all errors and add them at the end of the output (or at the top so it's more visible) by making use of output buffering.

Creating (but not throwing) the error exception already captures a back-trace which can be useful in error handling.

Another alternative to display the errors and warnings is to log them to the log-file and then monitor that file with another process and aggregate the information. You could create a scoreboard that display the number of warnings per application and make this visible in the office so everybody sees how well a team performs or some fun like that.

What I try to say is: Next to the technical problem, it's a social problem you need to be creative with and actually talk the problem out of your developers. You need to make clear why it's important to fix warnings and errors and how their coding and skills will benefit from that.

Solution 3:

As of PHP 5.3.0:

set_error_handler(
    function(int $nSeverity, string $strMessage, string $strFilePath, int $nLineNumber){
        if(error_reporting()!==0) // Not error suppression operator @
            throw new \ErrorException($strMessage, /*nExceptionCode*/ 0, $nSeverity, $strFilePath, $nLineNumber);
    },
    /*E_ALL*/ -1
);