László Monda
László Monda

Reputation: 1753

Trying to use a global exception handler in PHP to handle various toplevel exceptions in a unified manner

Please consider the following code:

<?php

class MyException extends Exception {}

function global_exception_handler($exception)
{
    switch (get_class($exception)) {
    case 'MyException':
        print "I am being handled in a unified way.\n";
        break;
    default:
        $backtrace = debug_backtrace();
        $exception_trace_object = $backtrace[0]['args'][0];
        var_dump($exception_trace_object);
        print "----\n";
        $reflected_exception_trace_object = new ReflectionObject($exception_trace_object);
        $reflected_trace_property = $reflected_exception_trace_object->getProperty('trace');
        $reflected_trace_property->setAccessible(true);
        var_dump($reflected_trace_property);
        print "----\n";

        // NOT WORKING, I STUCK HERE.
        var_dump($reflected_trace_property->getValue($reflected_trace_property));

        throw $exception;
    }
}

set_exception_handler('global_exception_handler');

function function1()
{
    function2();
}

function function2()
{
    function3();
}

function function3()
{
    throw new Exception();
}

function1();

?>

What I'm trying to do is handling various types of exceptions in a unified way across various files by simply setting up a global exception handler without having to write any boilerplate code (except the header and footer includes which are present in every file).

The problem is that when the thrown exception type is not handled by the global exception handler and I want to rethrow the exception, the stack trace gets lost which is a limitation of using set_exception_handler().

I can retrieve the stack trace by using debug_backtrace() but I cannot access its relevant private members to be able to print it appropriately.

This is what the above script produces:

object(Exception)#1 (7) {
  ["message":protected]=>
  string(0) ""
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(28) "/home/laci/download/test.php"
  ["line":protected]=>
  int(42)
  ["trace":"Exception":private]=>
  array(3) {
    [0]=>
    array(4) {
      ["file"]=>
      string(28) "/home/laci/download/test.php"
      ["line"]=>
      int(37)
      ["function"]=>
      string(9) "function3"
      ["args"]=>
      array(0) {
      }
    }
    [1]=>
    array(4) {
      ["file"]=>
      string(28) "/home/laci/download/test.php"
      ["line"]=>
      int(32)
      ["function"]=>
      string(9) "function2"
      ["args"]=>
      array(0) {
      }
    }
    [2]=>
    array(4) {
      ["file"]=>
      string(28) "/home/laci/download/test.php"
      ["line"]=>
      int(45)
      ["function"]=>
      string(9) "function1"
      ["args"]=>
      array(0) {
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
}
----
object(ReflectionProperty)#3 (2) {
  ["name"]=>
  string(5) "trace"
  ["class"]=>
  string(9) "Exception"
}
----
NULL

Fatal error: Exception thrown without a stack frame in Unknown on line 0

Thanks in advance!

Upvotes: 2

Views: 6929

Answers (1)

powtac
powtac

Reputation: 41050

Check the comments on http://php.net/manual/de/function.set-exception-handler.php there are several similar issues and solutions there. For your code I see two possible solutions:

Change your code into

function global_exception_handler($exception = NULL)

or add a description to

throw new Exception('Testing here...');

Upvotes: 5

Related Questions