Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Callback on Entry/Exit of Class Methods?

Is there a way I can set up callbacks on (or automataically log) method parameters, entries, and exits without making explicit calls within each method? I basically want to log this information to my logger class (which is static) without having to do it manually for each method.

Right now I have to call Logger::logEntry() and Logger::logExit() in every method to accomplish this. I would love to not have to do this:

class TestClass {
    public function tester($arg) {
        Logger::logEntry();
        Logger::info('Parameter $arg => ' . $arg);

        // Do some stuff...

        Logger::logExit();
    }
}
like image 293
Wilco Avatar asked Apr 18 '26 16:04

Wilco


2 Answers

use a wrapper class. this method has the following benefits:

  • no need to change your underlying class structure / method signatures
  • change logging? just update this class
  • update object calls vs inserting code into every class you want to log

.

class LogWatch {
    function __construct($class)    {
        $this->obj  =   $class;
    }

    function __call($method, $args) {
        if (in_array($method, get_class_methods($this->obj) ) ) {
            Logger::logEntry();
            Logger::info('Parameter '.implode(', ', $args) );

            call_user_func_array(array($this->obj, $method), $args);

            Logger::logExit();

        } else {
            throw new BadMethodCallException();
        }
    }
}

$test = new LogWatch(new TestClass() );
$test->tester();

// you can use instances of `LogWatch()` just like your watched class
// including passing appropriate params:
$test->tester($param1, $param2);
like image 186
Owen Avatar answered Apr 21 '26 06:04

Owen


If you want to do function logging for the sake of debugging you may want to look into the Xdebug extension. There's no good way to intercept function calls at at runtime, and any automated interception will add great runtime overhead.

Using XDebug you could instead turn it on as-needed, as well as get lots of other stuff

( XDebug is thus used with PHPUnit to do unit testing and coverage analysis. )

  • Xdebug
  • PHPUnit

The Problem with __call

__call may look to be a fun solution to the problem, but there are 3 problems with this, namely

  • Significant Execution Overhead. your doing __call --> call_user_func_array , which will literally add not one, but two function calls to every execution.

  • Backtraces become indecipherable: The actual function you were trying to call gets lost in a sea of __call and call_user_func_array making backtracing exceedingly hard, especially if your backtraces come with their arguent lists included.

  • Stupid Hidden Functions: You're going back to PHP4 style "hiding" of functions by prefixing them with _ to stop the user directly calling it or seeing it, because if the function name happens to be named what they wan't, the __call wont trigger, so you have already got a whole class full of really horrible function names, which developers will be tempted to call directly anyway in various places. ( And if you want to get rid of __call later, you will have to rename all these functions as to not break the code! )

Thus, if you are utilising php code to implement this will result in epically horrible code, that any future user of your codebase will NOT want to work with. You are far better getting something ( like Xdebug ) that can be added transparently when you need it, and save greatly polluting your code.

like image 40
Kent Fredric Avatar answered Apr 21 '26 05:04

Kent Fredric