How to turn E_PARSE errors into Exception in PHP?

Asked

Viewed 322 times

8

My question is this::

PHP has a great feature that lets you convert errors that can occur in an application into Exceptions. This can be done through class ErrorException

Example:

set_error_handler(function ($errno, $errstr, $errfile, $errline ) {

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);

});

try {
   $a = $b;
} catch(\Exception $e){
    echo $e->getMessage(); // Undefined variable: b

}

This "error capture" works perfectly for errors like E_NOTICE, E_WARNING etc... However, when a Parse Error (E_PARSE), the set_error_handler is not able to capture him.

I managed to (more or less) make this capture of E_PARSE through function register_register_shutdown_function (it executes a function when php ends the script, even if there is an interruption of execution on account of E_PARSE) in combination with the function error_get_last.

  1. I would like to know how to proceed to make this operation, so that occurs similarly in the capture of errors with the set_error_handler.
  2. How to proceed if display on the screen only the error (and not codes before execution). I will have to use a ob_start combined with one ob_end_clean inside the error "catcher"?

I’ll tell you in advance: To say that there is no way to do this is a lie, because the Laravel 4 can perfectly transform the E_PARSE except also!

inserir a descrição da imagem aqui

Updating

At user’s request @gmsantos, I am posting the transformation code of E_PARSE for ErrorException, that I think is as close as I am wanting.

That’s what I was able to do using the register_shutdown_function (was pretty fast, so there’s no object-oriented :) ):

<?php


ob_start();

echo 'Olá mundo'; 

// Por essa função, o try/catch consegue "pegar" a exceção
set_error_handler(function($errno, $errstr, $errfile, $errline){

    // Se o cara não colocar arroba, o erro é mostrado :)

    if (error_reporting() !== 0) {

        ob_clean(); // limpa o buffer e não imprime "Ólá mundo"

        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);

    }
});

// aqui não dá pra usar try/catch :(

register_shutdown_function(function(){

    // O register_shutdown_function só pode capturar E_PARSERs provenientes de include, e não no mesmo script

    if ($err = error_get_last()) {

        ob_clean(); // limpa o buffer e não imprime "Ólá mundo"

        throw new ErrorException($err['message'], 0, $err['type'], $err['file'], $err['line']);

        /*
            Uncaught exception 'ErrorException' with message 'syntax error, unexpected '.'' 
            in C:\xampp\htdocs\teste\teste.php:4 

            Stack trace: 

            #0 [internal function]: {closure}() 

            #1 {main} thrown in C:\xampp\htdocs\teste\teste.php on line 4
        */
    }

});

// Proprositalmente para gerar uma exception não capturada pelo set_error_handler

$a = @$a;

try {

    $b = $b;

} catch (Exception $e) {

    echo $e->getMessage(); 


    /*
        Se a variável "a" tiver um arroba colocado, essa mensagem é impressa!
        Nesse caso captura a exceção retorna: Undefined Variable: b
    */

}


try {

    include 'teste.php'; 

    /* 
        Esse include gera um E_PARSE, porém só é exibido no catch se for outros tipos de erro, 
        pois o register_shutdown_function é executado só quando o script é encerrado :(
        Não consegui capturar com o "catch"
    */

} catch(\ErrorException $ee) {

    echo $ee->getMessage(); // Esse não imprime nada, como dito acima
}

Just reinforcing what is already written in the example: There is no way to capture the E_PARSER in the try/catch (at least, in this script I did, there’s no way)

  • 4

    Actually it’s not Laravel that does it, but its debug components. Have you tried investigating the source code of Whoops (Laravel 4) or symfony/Debug (Laravel 5)?

  • Now that I know who is responsible (according to your information, @gmsantos), I will give a search yes. Thanks!

  • 3

    if you find the post answer here for us please ;)

  • 3

    see this method in Whoops: https://github.com/filp/whoops/blob/9e1ffa25c32db969b6ce0db73290ea272d896b11/src/Whoops/Run.php#L331 . I think it’s something like you said, manipulating the output buffer.

  • I really like PHP. But if it was a fully object-oriented (and more organized) language, I wouldn’t have to do so many paranauese (read "gambiarras" for some cases), to be able to do something that in other languages is much simpler to do!

  • 1

    PHP: love it or let it :) . The language is constantly evolving and a lot can change (read HHMV, Hack and PHPNG)

  • rsrsrsrsrsrsrs! is just a vent! I won’t let PHP not, it pays my salary.

  • ve this comment on the PHP website should help your implementation http://php.net/manual/en/function.set-error-handler.php#84345

Show 3 more comments

1 answer

3


Instead of giving throw in the ErrorException inside the callback of the register_shutdown_function, you can build a ErrorException and pass it to an Handler who will take care of the details.

<?php
function handleException(Exception $e) {
    echo $e->getMessage();
}

function handleError(array $error = null) {
    $err = error_get_last();

    if ($err) {
        $exception =  new ErrorException(
            $err['message'], 
            $err['type'], 
            1,  
            $error['file'], 
            $err['line']
        );
        handleException($exception);
    }
}

register_shutdown_function('handleError');

Browser other questions tagged

You are not signed in. Login or sign up in order to post.