Search code examples
phpooperror-handlingprocedural-programming

Custom error handler to handle errors inside and outside Object code


I do know there are already many questions on Stackoverflow related to custom error handlers. But, after reading many of them, as well as the PHP manual, I am still unable to solve my problem. Thus I am posting this question.

My script is currently structured this way:

require 'file.php';
require 'anotherFile.php';
// several more "require" here. These files contain many functions

function myErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
    // some code to handle errors here
    
}

class myObject {
    function __construct() {
        // set the values here
    }

    function computeSomething() {
        ...
        doFunction2();
        ...
    }

    function SomethingBadHappened()
    {
    }
}

function doFunction1() {
    // for some reason, an error happens here
    // it is properly handled by the current error handler
}

function doFunction2() {
    // for some reason, an error happens here
    // since it got called by $obj, I want the error handler to run $obj->SomethingBadHappened();
    // but $obj is not known in myErrorHandler function!
}

set_error_handler('myErrorHandler');

// some procedural code here
doFunction1();
doAnotherThing();

// then I use objects
$obj = new myObject();
$obj->run();

// then I may use procedural code again
doSomethingElse();

My custom error handler is already working fine. It catches and processes all PHP errors that occur in the code executed after the error handler is set.

My problem:

If an error occurs within a method of myObject class, I would like to call a non-static method:

$obj->SomethingBadHappened();

$obj is not in the scope of myErrorHandler. How can I access $obj inside the error handler to call a member function of $obj?
I currently have 300KB of PHP code, and I can't change the signature of all the functions to add $obj as a parameter (there are too many functions!).

I read that it is possible to define the custom error handler as a method of an object. But, if I do that, it won't be able to catch errors that happen before creating the instance of myObject ($obj).

I also read about exceptions, but it doesn't seem to help solving my problem. I am not willing to use global variables. Here are 2 questions that explain why global variables should be avoided:


Solution

  • I finally decided for this design:

    • my current error handler remains unchanged (function myErrorHandler). It holds the code to be executed when an error happens (anywhere in the code)
    • in the class myObject I added another error handler (function myObject_error_handler)
    • the constructor of myObject registers the new error handler
    • the function myObject_error_handler may now call the function SomethingBadHappened, then calls myErrorHandler to process the error

    The major benefit of doing so it that it required very few changes to the existing code:

    • one new method in my class
    • register the new error handler in the constructor
    • a call to the older error handler from the new error handler

    The new code is:

    require 'file.php';
    require 'anotherFile.php';
    // several more "require" here. These files contain many functions
    
    function myErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
        // some code to handle errors here
    
    }
    
    class myObject {
        function __construct() {
            // set the values here
    
            // register another error handler
            set_error_handler(array($this, 'myObject_error_handler'));
        }
    
        function myObject_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
            // call any number of methods of the current class
            $this->SomethingBadHappened();
    
            // then call the other error handler
            myErrorHandler($errno, $errstr, $errfile, $errline, $errcontext);
        }
    
        function computeSomething() {
            ...
            doFunction2();
            ...
        }
    
        function SomethingBadHappened() {
            // does something when an error happens
        }
    }
    
    function doFunction1() {
        // for some reason, an error happens here
        // it is properly handled by the current error handler
    }
    
    function doFunction2() {
        // for some reason, an error happens here
        // now the function myObject_error_handler will be called automatically
    }
    
    set_error_handler('myErrorHandler');
    
    // some procedural code here
    doFunction1();
    doAnotherThing();
    
    // then I use objects
    $obj = new myObject();
    $obj->run();
    
    // then I may use procedural code again
    set_error_handler('myErrorHandler');
    doSomethingElse();