* @copyright Copyright 2007-2010, Gravity Boulevard, LLC * @license http://www.opensource.org/licenses/mit-license.html * @package PICKLES * @link http://p.ickl.es */ /** * Profiler Class * * The Profiler class is statically interfaced with and allows for in depth * profiling of a site. By default profiling is off, but can be enabled in the * config.ini for a site. Out of the box the profiler will report on every * class object in the system that extends the code Object class. * * Note: I really wanted to use PHP Quick Profiler by Ryan Campbell of * Particletree but it kept barking out errors when I tried to use it with * E_STRICT turned on. Here's a link anyway since it looks awesome: * http://particletree.com/features/php-quick-profiler/ * * @usage Profiler::log('some action you want to track'); * @usage Profiler::log($object, 'methodName'); */ class Profiler { /** * Config * * Profiler configuration * * @static * @access private * @var array */ private static $config; /** * Profile * * Array of logged events * * @static * @access private * @var array */ private static $profile = array(); /** * Queries * * Number of queries that have been logged * * @static * @access private * @var integer */ private static $queries = 0; /** * Timers * * Array of active timers * * @static * @access private * @var array */ private static $timers = array(); /** * Constructor * * Private constructor since this class is interfaced wtih statically. * * @access private */ private function __construct() { } /** * Enabled * * Checks if the profiler is set to boolean true or if the passed type is * specified in the profiler configuration value. * * @param array $type type(s) to check * @return boolean whether or not the type is enabled */ public static function enabled(/* polymorphic */) { // Grabs the config object if we don't have one yet if (self::$config == null) { $config = Config::getInstance(); self::$config = $config->pickles['profiler']; } // Checks if we're set to boolean true if (self::$config === true) { return true; } else { $types = func_get_args(); foreach ($types as $type) { if (stripos(self::$config, $type) !== false) { return true; } } } return false; } /** * Log * * Logs the event to be displayed later on. Due to the nature of how much * of a pain it is to determine which class method called this method I * opted to make the method a passable argument for ease of use. Perhaps * I'll revisit in the future. Handles all elapsed time calculations and * memory usage. * * @static * @param mixed $data data to log * @param string $method name of the class method being logged */ public static function log($data, $method = false, $type = false) { $time = microtime(true); $data_type = ($data == 'timer' ? $data : gettype($data)); // Tidys the data by type switch ($data_type) { case 'array': $log = '
' . print_r($data, true) . '
'; break; case 'object': $log = '[' . get_parent_class($data) . '] ' . '' . get_class($data) . '' . ($method != '' ? '->' . $method . '()' : ''); $data_type = '' . $data_type . ''; break; case 'timer': $log = $method; $data_type = '' . $data_type . ''; break; case 'string': default: if ($type != false) { $data_type = $type; } $log = $data; break; } self::$profile[] = array( 'log' => $log, 'type' => $data_type, 'time' => $time, 'elapsed' => $time - PICKLES_START_TIME, 'memory' => memory_get_usage(), ); } /** * Log Query * * Serves as a wrapper to get query data to the log function * * @static * @param string $query the query being executed * @param array $input_parameters optional prepared statement data * @param array $explain EXPLAIN data for the query * @param float $duration the speed of the query */ public static function logQuery($query, $input_parameters = false, $explain = false, $duration = false) { self::$queries++; $log = ''; if ($input_parameters != 'false' && is_array($input_parameters)) { $log .= '
'; foreach ($input_parameters as $key => $value) { $log .= '
' . $key . ' => ' . $value . ''; $query = str_replace($key, '' . $key . '', $query); } } $log = '' . $query . '' . $log; if (is_array($explain)) { $log .= '
'; foreach ($explain as $table) { $log .= '
Possible Keys => ' . ($table['possible_keys'] == '' ? 'NONE' : $table['possible_keys']) . '' . '
Key => ' . ($table['key'] == '' ? 'NONE' : $table['key']) . '' . '
Type => ' . $table['type'] . '' . '
Rows => ' . $table['rows'] . '' . ($table['Extra'] != '' ? '
Extra => ' . $table['Extra'] . '' : ''); } } $log .= '

Speed: ' . number_format($duration * 100, 3) . ' ms'; self::log($log, false, 'database'); } /** * Timer * * Logs the start and end of a timer. * * @param string $timer name of the timer * @return boolean whether or not timer profiling is enabled */ public static function timer($timer) { if (self::enabled('timers')) { // Starts the timer if (!isset(self::$timers[$timer])) { self::$timers[$timer] = microtime(true); self::Log('timer', 'Started timer ' . $timer . ''); } // Ends the timer else { self::Log('timer', 'Stopped timer ' . $timer . ' => Time Elapsed: ' . number_format((microtime(true) - self::$timers[$timer]) * 100, 3) . ' ms'); unset(self::$timers[$timer]); } return true; } return false; } /** * Report * * Generates the Profiler report that is displayed by the Controller. * Contains all the HTML needed to display the data properly inline on the * page. Will generally be displayed after the closing HTML tag. */ public static function report() { $start_time = PICKLES_START_TIME; $peak_usage = self::formatSize(memory_get_peak_usage()); $end_time = self::$profile[count(self::$profile) - 1]['time']; $duration = ($end_time - $start_time); $logs = count(self::$profile); $logs .= ' Log' . ($logs == 1 ? '' : 's'); $files = count(get_included_files()); $files .= ' File' . ($files == 1 ? '' : 's'); $queries = self::$queries . ' Quer'. (self::$queries == 1 ? 'y' : 'ies'); ?>
PICKLES Profiler

Console
Load Time
Memory Usage
Database
Includes
$entry) { ?>
Console Memory Time
ms