<?php
/**
* This file contains the profiler class that allows to profile the performances of the PHP scripts.
* It allows to export the profile report in CSV and XML format.
*
* @package profiler
*/
/**
* PROFILE_FILE_TYPE_CSV Constant
*
* It's used in the {@link profiler::profiler()} class to specify which kind of out file will be produced
* @see profiler::profiler()
*/
define ('PROFILE_FILE_TYPE_CSV', 0);
/**
* PROFILE_FILE_TYPE_XML Constant
*
* It's used in the {@link profiler::profiler()} class to specify which kind of out file will be produced
* @see profiler::profiler()
*/
define ('PROFILE_FILE_TYPE_XML', 1);
/**
* PROFILE_CONFIG_PERCENT_DECIMAL Constant
*
* Here you can specify the number of decimal to be used in the elasped time percentage.
*/
define ('PROFILE_CONFIG_PERCENT_DECIMAL', 4);
/**
* PROFILE_LOCALIZE_DECIMAL_POINT Constant
*
* Here you can specify yor decimal separator, usefull for a correct CSV exportation.
*/
define ('PROFILE_LOCALIZE_DECIMAL_POINT', ',');
/**
* PROFILE_LOCALIZE_THOUSAND_SEPARATOR Constant
*
* Here you can specify yor thousand separator, usefull for a correct CSV exportation.
*/
define ('PROFILE_LOCALIZE_THOUSAND_SEPARATOR', '');
/**
* profiler class
*
* This class allows to profile your script performances.
*
* @package profiler
* @author Setec Astronomy
* @version 1.0
* @abstract Profile your PHP scripts
* @copyright 2004
* @example example.php An example of this class usage
*/
class profiler {
/**
* @access private
*/
var $profiles = array ();
/**
* @access private
*/
var $filename = array ();
/**
* @access private
*/
var $file_type = array ();
/**
* Default constructor
*
* This is the default constructor of profiler class.
*<code>
*require_once (dirname (__FILE__) . '/profiler.class.php');
*$profiler = new profiler ('test.csv', PROFILE_FILE_TYPE_CSV);
*declare (ticks=1);
*
*Your code goes here!
*
*</code>
*/
// public function profiler () {
function profiler ($filename, $file_type = PROFILE_FILE_TYPE_TXT) {
$this->profiles = array ();
$this->filename = $filename;
$this->file_type = $file_type;
register_shutdown_function (array (&$this, 'saveProfiles'));
register_tick_function (array (&$this, 'handleTicks'));
}
/**
* @access private
*/
// private function safe_set (&$var_true, $var_false = '')
function safe_set (&$var_true, $var_false = '') {
if (!isset ($var_true)) {
$var_true = $var_false;
}
return $var_true;
}
/**
* @access private
*/
// private file_put_contents ($filename, $content) {
function file_put_contents ($filename, $content) {
if (is_dir (dirname ($filename))) {
if (function_exists ('file_put_contents')) {
return file_put_contents ($filename, $content);
} else {
$fd = fopen ($filename, "wb");
$return = fwrite ($fd, $content);
fclose ($fd);
return $return;
}
}
return false;
}
/**
* @access private
*/
// private function getMicrotime () {
function getMicrotime () {
list ($usec, $sec) = explode (' ', microtime ());
return ((float)$usec + (float)$sec);
}
/**
* @access private
*/
// private function handleTicks () {
function handleTicks () {
$debug = debug_backtrace ();
if (isset ($debug[1])) {
$last = $debug[1];
$code_line = '';
if (isset ($last['file']) && isset ($last['line'])) {
$lines = file ($last['file']);
if (isset ($lines[$last['line'] - 1])) {
$code_line = ($lines[$last['line'] - 1]);
} else {
$code_line = 'EOF';
}
}
$now = $this->getMicrotime ();
$last['microtime'] = sprintf('%.16f', $now);
$last['elasped'] = sprintf('%.16f', 0);
$last['code'] = trim ($code_line);
if ($last['function'] == 'unknown') {
$last['function'] = '';
}
$this->profiles[] = $last;
}
}
/**
* @access private
*/
// private function saveProfiles () {
function saveProfiles () {
unregister_tick_function (array (&$this, 'handleTicks'));
@array_shift ($this->profiles); // shift "register_tick_function (array (&$this, 'handleTicks'));"
@array_shift ($this->profiles); // shift first "declare (ticks=1);"
@array_shift ($this->profiles); // shift second "declare (ticks=1);"
$now = $this->getMicrotime ();
$output = '';
$count = count ($this->profiles);
if ($count > 0) {
$this->safe_set ($this->profiles[$count - 1]['microtime']);
$this->safe_set ($this->profiles[0]['microtime']);
$total_elasped = sprintf ('%.16f', $this->profiles[$count - 1]['microtime'] - $this->profiles[0]['microtime']);
if ($total_elasped > 0) {
switch ($this->file_type) {
case PROFILE_FILE_TYPE_CSV:
$output .= '"Row";"FileName";"Line";"Function";"Microtime";"Elasped";"Code";"Percentage"' . "\r\n";
break;
case PROFILE_FILE_TYPE_XML:
$output .= '<?xml version="1.0" encoding="iso-8859-1" ?' .'>' . "\r\n";
$output .= "<profiler>\r\n";
$output .= "\t<profiles>\r\n";
break;
}
for ($i = 0; $i < $count; $i ++) {
$this->safe_set ($this->profiles[$i]['file']);
$this->safe_set ($this->profiles[$i]['line']);
$this->safe_set ($this->profiles[$i]['function']);
$this->safe_set ($this->profiles[$i]['microtime']);
$this->safe_set ($this->profiles[$i]['code']);
$this->safe_set ($this->profiles[$i]['elasped'], 0);
if ($i == $count - 1) {
$this->profiles[$i]['elasped'] = sprintf ('%.16f', $now - $this->profiles[$i]['microtime']);
} else {
$this->profiles[$i]['elasped'] = sprintf ('%.16f', $this->profiles[$i + 1]['microtime'] - $this->profiles[$i]['microtime']);
}
$this->profiles[$i]['elasped_percent'] = (100 * $this->profiles[$i]['elasped']) / $total_elasped;
$elasped_percent = number_format ($this->profiles[$i]['elasped_percent'], PROFILE_CONFIG_PERCENT_DECIMAL, PROFILE_LOCALIZE_DECIMAL_POINT, PROFILE_LOCALIZE_THOUSAND_SEPARATOR) . ' %';
$elasped = number_format ($this->profiles[$i]['elasped'], 16, PROFILE_LOCALIZE_DECIMAL_POINT, PROFILE_LOCALIZE_THOUSAND_SEPARATOR);
$microtime = number_format ($this->profiles[$i]['microtime'], 16, PROFILE_LOCALIZE_DECIMAL_POINT, PROFILE_LOCALIZE_THOUSAND_SEPARATOR);
$code = str_replace ('"', '""', $this->profiles[$i]['code']);
switch ($this->file_type) {
case PROFILE_FILE_TYPE_CSV:
$output .= '"' . $i . '";"' . $this->profiles[$i]['file'] . '";"' . $this->profiles[$i]['line'] . '";"' .
$this->profiles[$i]['function'] . '";"' . $microtime . '";"' .
$elasped . '";"' . $code . '";"' .
$elasped_percent . '"' . "\r\n";
break;
case PROFILE_FILE_TYPE_XML:
$output .= "\t\t<profile id='" . $i . "'>\r\n";
$output .= "\t\t\t<file>" . htmlentities ($this->profiles[$i]['file']) . "</file>\r\n";
$output .= "\t\t\t<line>" . $this->profiles[$i]['line'] . "</line>\r\n";
$output .= "\t\t\t<function>" . $this->profiles[$i]['function'] . "</function>\r\n";
$output .= "\t\t\t<microtime>" . $microtime . "</microtime>\r\n";
$output .= "\t\t\t<elasped>" . $elasped . "</elasped>\r\n";
$output .= "\t\t\t<code>" . htmlentities ($this->profiles[$i]['code']) . "</code>\r\n";
$output .= "\t\t\t<elasped_percent>" . $elasped_percent . "</elasped_percent>\r\n";
$output .= "\t\t</profile>\r\n";
break;
}
}
switch ($this->file_type) {
case PROFILE_FILE_TYPE_CSV:
break;
case PROFILE_FILE_TYPE_XML:
$output .= "\t</profiles>\r\n";
$output .= "</profiler>\r\n";
break;
}
}
}
$this->file_put_contents ($this->filename, $output);
}
}
?>