tags:

views:

239

answers:

4

To clarify:

I'm building a Logger class that allows me to easily log messages:

lib.Logger.php:

<?php
class Logger {
    private $handle;

    public function __construct($log_name, $log_path) {

        if ( ! is_dir($log_path))
            throw new Exception('Log path does not exist.');

        if ( ! in_array(strtolower(substr($log_name, 0, -4)), array('.log', '.txt')))
            $log_name = "{$log_name}.log";

        $this->handle = fopen("{$log_path}/{$log_name}", 'a');

        $this->log('------------- Initializing ------------- '.get_parent_class($this));
    }

    // --------------------------------------------------------------------

    public function __destruct() {
        fclose($this->handle);
    }

    // --------------------------------------------------------------------

    public function log($message) {
        $time = date(DATE_RFC822);

        $log = "[{$time}] {$message}\n";

        fwrite($this->handle, $log);
    }    

}

?>

And I call this using:

MyController.php:

<?php
class MyController extends Controller {
    $logger = new Logger('testlog','/path/to/logs/');
    $logger->log('Logs are fun!');
}
?>

When I initialize the object:

 $this->log('------------- Initializing ------------- '.get_parent_class($this));

I want to log the name of the object (or file) that is calling log() -- in this case, either

MyController
or
/path/to/MyController.php
.

I tried using get_parent_class(), but of course this doesn't work because Logger does not have a parent class per se.

Any ideas? thank you so much for the help!

Alex B

+1  A: 

You willl need to make use of the function debug_backtrace(). But note that the function is not very consistent in its return value (not every array key is always present, even if it should be - the index file can be missing, for example, indicating that the file is either unknown (eval'd code) or the same as the previous stack frame). The last function that was called before this one should be available at index 0:

$trace = debug_backtrace();
$calling_function = $trace[0]['function'];
soulmerge
+3  A: 

Hi,

I suppose a solution could be to use debug_backtrace.

The given example gets a backtrace like this :

array(2) {
[0]=>
array(4) {
    ["file"] => string(10) "/tmp/a.php"
    ["line"] => int(10)
    ["function"] => string(6) "a_test"
    ["args"]=>
    array(1) {
      [0] => &string(6) "friend"
    }
}
[1]=>
array(4) {
    ["file"] => string(10) "/tmp/b.php"
    ["line"] => int(2)
    ["args"] =>
    array(1) {
      [0] => string(10) "/tmp/a.php"
    }
    ["function"] => string(12) "include_once"
  }
}

So, should include what you want ;-)


Still, the solution that seems the best, in my opinion, would be to pass the information needed when calling the log method...
(Just feels more... natural ^^ But that's not a very rational opinion, I suppose ^^ )

Pascal MARTIN
+1  A: 

The only way to handle this implicitly is to capture the output from debug_backtrace as the others have suggested.

If you are interested in an explicit approach, maybe this could be it

in Logger

public function initialize( $context )
{
  $logMessage = '------------- Initializing ------------- ';
  if ( is_object( $context ) )
  {
    $logMessage .= get_class( $context );
  } else {
    // do something else?
  }
  $this->log( $logMessage );
}

and then

class MyController extends Controller
{
  public function someFunc()
  {
    $logger = new Logger('testlog','/path/to/logs/');
    $logger->initialize( $this );
    $logger->log('Logs are fun!');
  }
}
Peter Bailey
A: 

I ran into (almost) this exact problem last night. I'm using debug_backtrace() (as many others have already mentioned) to solve it. I needed to know the module that contains the controller that was calling a certain function. Because my controllers contain the module name within the class name, I simply grabbed the return from debug_backtrace() and explode()ed it to fetch the module name.

Soulmerge makes a good point about the return not always being consistent, but if you structure your code a certain way you can definitely get an accurate enough return.

Arms