<?php
/**
* Class for postdebugging of program flow
*
* It helps you to eliminate delays, long cycles,
* improve program logics and so.
*
* (This class actually is the part of original
* UltimaPHP package)
*
* @version 0.2b 28/05/2010
* @package UltimaPHPCore
* @author Epsilon (http://epsiloncool.elance.com)
* @link http://ultimaphp.ru - UltimaPHP Home
*
*/
class uDebug
{
/**
* Reference to class instance
*
* @var uDebug
*/
private static $instance;
/**
* Tracking array
*
* @var array
*/
public static $track = array();
/**
* Index of current processing track item
*
* @var int
*/
protected static $current = -1;
/**
* Singleton creating and inspection function
*
* @return uDebug
*/
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
self::create();
}
return self::$instance;
}
static function create() {
self::$track = array();
}
/**
* Method to start new subblock
*
* @param string $name Block group name
* @param mixed $data Any data to assign with this block
*/
static function openMarker($name, $data = false) {
$time = microtime(true);
self::$track[] = array(self::$current, $name, $time, $data);
self::$current = count(self::$track) - 1;
}
/**
* Method to close current subblock
*
*/
static function closeMarker() {
$time = microtime(true);
if (self::$current >= 0) {
self::$track[self::$current][4] = $time - self::$track[self::$current][2]; // Length in time
self::$current = self::$track[self::$current][0];
} else {
throw new Exception('Marker closing without no marker open');
}
}
/**
* Returns final report as linear array
*
* @return array
*/
static function report_Array() {
return print_r(self::$track, true);
}
/**
* Returns final report as multidimensional XML
*
* @return SimpleXMLElement
*/
static function report_XML() {
$xml = simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><uDebugReport/>');
$refnodes = array();
foreach (self::$track as $k => $d) {
$parent = $d[0];
if ($parent >= 0) {
$refnodes[$k] = $refnodes[$parent]->addChild('n');
$refnodes[$k]->addAttribute('name', htmlentities(addslashes($d[1])));
$refnodes[$k]->addAttribute('t', htmlentities(addslashes(sprintf('%.8f', $d[4]))));
$refnodes[$k]->addAttribute('data', htmlentities(addslashes($d[3])));
} else {
$refnodes[$k] = $xml[0]->addChild('n');
$refnodes[$k]->addAttribute('name', htmlentities(addslashes($d[1])));
$refnodes[$k]->addAttribute('t', htmlentities(addslashes(sprintf('%.8f', $d[4]))));
$refnodes[$k]->addAttribute('data', htmlentities(addslashes($d[3])));
}
}
return $xml;
}
/**
* Returns formatted and indented XML string
*
* @param string $xml Input XML as string
* @param bool $html_output true if htmlentities is required
* @return string Output indented and formatted XML
*/
static function indentedXML($xml, $html_output=false) {
$level = 4;
$indent = 0; // current indentation level
$pretty = array();
// get an array containing each XML element
$xml = explode("\n", preg_replace('/>\s*</', ">\n<", $xml));
// shift off opening XML tag if present
if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {
$pretty[] = array_shift($xml);
}
foreach ($xml as $el) {
if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) {
// opening tag, increase indent
$pretty[] = str_repeat(' ', $indent) . $el;
$indent += $level;
} else {
if (preg_match('/^<\/.+>$/', $el)) {
$indent -= $level; // closing tag, decrease indent
}
if ($indent < 0) {
$indent += $level;
}
$pretty[] = str_repeat(' ', $indent) . $el;
}
}
$xml = implode("\n", $pretty);
return ($html_output) ? htmlentities($xml) : $xml;
}
}
// Create singleton
uDebug::singleton();