Code Snippets 2.5.0 brings PHP error detection

Code Snippets version 2.5.0 has just been released. It is not a large update, but includes a change that many people have been requesting for a long time: detection of errors in snippet code. As usual, you can download Code Snippets from WordPress.org and browse the code at GitHub. I’m going to use the rest of this post to explain how things work on the PHP side of things.

How to implement this feature has been puzzling me for some time, as it’s very difficult to do things like deactivating snippets and catching fatal errors when the snippets are being executed on the site. The missing step was to attempt to execute the code before saving an active snippet to the database. This way, parse and fatal errors are triggered before the code is applied to the whole site.

For parse errors, the snippet is disabled and a message is shown on the page. Normally, PHP errors resulting from eval’d code look rather confusing. By using the error_get_last() function, it’s possible to produce a message that makes more sense to the user. Here’s an example of how that would work:

ob_start();
$result = eval( $code );
ob_end_clean();

if ( false === $result ) {
    $error = error_get_last();
    printf( '<p>An error occurred on line %d:<br>%s</p>', $error['line'], $error['message'] );
}

As you can see, we can tell that a parse error has occurred when eval() returns false. However, when a fatal error occurs, the entire script halts execution, even when it occurred inside an eval statement. While there is no way to recover from a fatal error, it is again possible to make the error message more user-friendly.

The key here is that ob_start() allows you to pass in a callback function. The callback acts as a filter, receiving the output as string and returning the content to be passed to the browser. In this callback, we can again use error_get_last() to display a more appropriate message.

$handler = function ( $out ) {
    $error = error_get_last();

    if ( is_null( $error ) ) {
        return $out;
    }

    return sprintf( '<p>An fatal error occurred on line %d:</p>%s', $error['line'], $error['message'] );
};

ob_start( $handler );
$result = eval( $code );
ob_end_clean();

 

There are 4 comments Join the conversation

Join the conversation

Your email address will not be published. Required fields are marked *