Modules

Debug
extends Kohana_Debug

Contains debugging and dumping tools.

package
Kohana
category
Base
author
Kohana Team
copyright
© 2008-2012 Kohana Team
license
http://kohanaphp.com/license

Class declared in SYSPATH/classes/Debug.php on line 3.

Constants

  • None

Properties

  • None

Methods

public static dump( mixed $value [, integer $length = integer 128 , integer $level_recursion = integer 10 ] ) (defined in Kohana_Debug)

Returns an HTML string of information about a single variable.

Borrows heavily on concepts from the Debug class of Nette.

Parameters

  • mixed $value required - Variable to dump
  • integer $length = integer 128 - Maximum length of strings
  • integer $level_recursion = integer 10 - Recursion limit

Return Values

  • string

Source Code

public static function dump($value, $length = 128, $level_recursion = 10)
{
	return Debug::_dump($value, $length, $level_recursion);
}

public static path( string $file ) (defined in Kohana_Debug)

Removes application, system, modpath, or docroot from a filename, replacing them with the plain text equivalents. Useful for debugging when you want to display a shorter path.

// Displays SYSPATH/classes/kohana.php
echo Debug::path(Kohana::find_file('classes', 'kohana'));

Parameters

  • string $file required - Path to debug

Return Values

  • string

Source Code

public static function path($file)
{
	if (strpos($file, APPPATH) === 0)
	{
		$file = 'APPPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(APPPATH));
	}
	elseif (strpos($file, SYSPATH) === 0)
	{
		$file = 'SYSPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(SYSPATH));
	}
	elseif (strpos($file, MODPATH) === 0)
	{
		$file = 'MODPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(MODPATH));
	}
	elseif (strpos($file, DOCROOT) === 0)
	{
		$file = 'DOCROOT'.DIRECTORY_SEPARATOR.substr($file, strlen(DOCROOT));
	}

	return $file;
}

public static source( string $file , integer $line_number [, integer $padding = integer 5 ] ) (defined in Kohana_Debug)

Returns an HTML string, highlighting a specific line of a file, with some number of lines padded above and below.

// Highlights the current line of the current file
echo Debug::source(__FILE__, __LINE__);

Parameters

  • string $file required - File to open
  • integer $line_number required - Line number to highlight
  • integer $padding = integer 5 - Number of padding lines

Return Values

  • string - Source of file
  • FALSE - File is unreadable

Source Code

public static function source($file, $line_number, $padding = 5)
{
	if ( ! $file OR ! is_readable($file))
	{
		// Continuing will cause errors
		return FALSE;
	}

	// Open the file and set the line position
	$file = fopen($file, 'r');
	$line = 0;

	// Set the reading range
	$range = array('start' => $line_number - $padding, 'end' => $line_number + $padding);

	// Set the zero-padding amount for line numbers
	$format = '% '.strlen($range['end']).'d';

	$source = '';
	while (($row = fgets($file)) !== FALSE)
	{
		// Increment the line number
		if (++$line > $range['end'])
			break;

		if ($line >= $range['start'])
		{
			// Make the row safe for output
			$row = htmlspecialchars($row, ENT_NOQUOTES, Kohana::$charset);

			// Trim whitespace and sanitize the row
			$row = '<span class="number">'.sprintf($format, $line).'</span> '.$row;

			if ($line === $line_number)
			{
				// Apply highlighting to this row
				$row = '<span class="line highlight">'.$row.'</span>';
			}
			else
			{
				$row = '<span class="line">'.$row.'</span>';
			}

			// Add to the captured source
			$source .= $row;
		}
	}

	// Close the file
	fclose($file);

	return '<pre class="source"><code>'.$source.'</code></pre>';
}

public static trace( [ array $trace = NULL ] ) (defined in Kohana_Debug)

Returns an array of HTML strings that represent each step in the backtrace.

// Displays the entire current backtrace
echo implode('<br/>', Debug::trace());

Parameters

  • array $trace = NULL - $trace

Return Values

  • string

Source Code

public static function trace(array $trace = NULL)
{
	if ($trace === NULL)
	{
		// Start a new trace
		$trace = debug_backtrace();
	}

	// Non-standard function calls
	$statements = array('include', 'include_once', 'require', 'require_once');

	$output = array();
	foreach ($trace as $step)
	{
		if ( ! isset($step['function']))
		{
			// Invalid trace step
			continue;
		}

		if (isset($step['file']) AND isset($step['line']))
		{
			// Include the source of this step
			$source = Debug::source($step['file'], $step['line']);
		}

		if (isset($step['file']))
		{
			$file = $step['file'];

			if (isset($step['line']))
			{
				$line = $step['line'];
			}
		}

		// function()
		$function = $step['function'];

		if (in_array($step['function'], $statements))
		{
			if (empty($step['args']))
			{
				// No arguments
				$args = array();
			}
			else
			{
				// Sanitize the file path
				$args = array($step['args'][0]);
			}
		}
		elseif (isset($step['args']))
		{
			if ( ! function_exists($step['function']) OR strpos($step['function'], '{closure}') !== FALSE)
			{
				// Introspection on closures or language constructs in a stack trace is impossible
				$params = NULL;
			}
			else
			{
				if (isset($step['class']))
				{
					if (method_exists($step['class'], $step['function']))
					{
						$reflection = new ReflectionMethod($step['class'], $step['function']);
					}
					else
					{
						$reflection = new ReflectionMethod($step['class'], '__call');
					}
				}
				else
				{
					$reflection = new ReflectionFunction($step['function']);
				}

				// Get the function parameters
				$params = $reflection->getParameters();
			}

			$args = array();

			foreach ($step['args'] as $i => $arg)
			{
				if (isset($params[$i]))
				{
					// Assign the argument by the parameter name
					$args[$params[$i]->name] = $arg;
				}
				else
				{
					// Assign the argument by number
					$args[$i] = $arg;
				}
			}
		}

		if (isset($step['class']))
		{
			// Class->method() or Class::method()
			$function = $step['class'].$step['type'].$step['function'];
		}

		$output[] = array(
			'function' => $function,
			'args'     => isset($args)   ? $args : NULL,
			'file'     => isset($file)   ? $file : NULL,
			'line'     => isset($line)   ? $line : NULL,
			'source'   => isset($source) ? $source : NULL,
		);

		unset($function, $args, $file, $line, $source);
	}

	return $output;
}

public static vars( ) (defined in Kohana_Debug)

Returns an HTML string of debugging information about any number of variables, each wrapped in a "pre" tag:

// Displays the type and value of each variable
echo Debug::vars($foo, $bar, $baz);

Return Values

  • string

Source Code

public static function vars()
{
	if (func_num_args() === 0)
		return;

	// Get all passed variables
	$variables = func_get_args();

	$output = array();
	foreach ($variables as $var)
	{
		$output[] = Debug::_dump($var, 1024);
	}

	return '<pre class="debug">'.implode("\n", $output).'</pre>';
}

protected static _dump( mixed & $var [, integer $length = integer 128 , integer $limit = integer 10 , integer $level = integer 0 ] ) (defined in Kohana_Debug)

Helper for Debug::dump(), handles recursion in arrays and objects.

Parameters

  • byref mixed $var required - Variable to dump
  • integer $length = integer 128 - Maximum length of strings
  • integer $limit = integer 10 - Recursion limit
  • integer $level = integer 0 - Current recursion level (internal usage only!)

Return Values

  • string

Source Code

protected static function _dump( & $var, $length = 128, $limit = 10, $level = 0)
{
	if ($var === NULL)
	{
		return '<small>NULL</small>';
	}
	elseif (is_bool($var))
	{
		return '<small>bool</small> '.($var ? 'TRUE' : 'FALSE');
	}
	elseif (is_float($var))
	{
		return '<small>float</small> '.$var;
	}
	elseif (is_resource($var))
	{
		if (($type = get_resource_type($var)) === 'stream' AND $meta = stream_get_meta_data($var))
		{
			$meta = stream_get_meta_data($var);

			if (isset($meta['uri']))
			{
				$file = $meta['uri'];

				if (function_exists('stream_is_local'))
				{
					// Only exists on PHP >= 5.2.4
					if (stream_is_local($file))
					{
						$file = Debug::path($file);
					}
				}

				return '<small>resource</small><span>('.$type.')</span> '.htmlspecialchars($file, ENT_NOQUOTES, Kohana::$charset);
			}
		}
		else
		{
			return '<small>resource</small><span>('.$type.')</span>';
		}
	}
	elseif (is_string($var))
	{
		// Clean invalid multibyte characters. iconv is only invoked
		// if there are non ASCII characters in the string, so this
		// isn't too much of a hit.
		$var = UTF8::clean($var, Kohana::$charset);

		if (UTF8::strlen($var) > $length)
		{
			// Encode the truncated string
			$str = htmlspecialchars(UTF8::substr($var, 0, $length), ENT_NOQUOTES, Kohana::$charset).'&nbsp;&hellip;';
		}
		else
		{
			// Encode the string
			$str = htmlspecialchars($var, ENT_NOQUOTES, Kohana::$charset);
		}

		return '<small>string</small><span>('.strlen($var).')</span> "'.$str.'"';
	}
	elseif (is_array($var))
	{
		$output = array();

		// Indentation for this variable
		$space = str_repeat($s = '    ', $level);

		static $marker;

		if ($marker === NULL)
		{
			// Make a unique marker
			$marker = uniqid("\x00");
		}

		if (empty($var))
		{
			// Do nothing
		}
		elseif (isset($var[$marker]))
		{
			$output[] = "(\n$space$s*RECURSION*\n$space)";
		}
		elseif ($level < $limit)
		{
			$output[] = "<span>(";

			$var[$marker] = TRUE;
			foreach ($var as $key => & $val)
			{
				if ($key === $marker) continue;
				if ( ! is_int($key))
				{
					$key = '"'.htmlspecialchars($key, ENT_NOQUOTES, Kohana::$charset).'"';
				}

				$output[] = "$space$s$key => ".Debug::_dump($val, $length, $limit, $level + 1);
			}
			unset($var[$marker]);

			$output[] = "$space)</span>";
		}
		else
		{
			// Depth too great
			$output[] = "(\n$space$s...\n$space)";
		}

		return '<small>array</small><span>('.count($var).')</span> '.implode("\n", $output);
	}
	elseif (is_object($var))
	{
		// Copy the object as an array
		$array = (array) $var;

		$output = array();

		// Indentation for this variable
		$space = str_repeat($s = '    ', $level);

		$hash = spl_object_hash($var);

		// Objects that are being dumped
		static $objects = array();

		if (empty($var))
		{
			// Do nothing
		}
		elseif (isset($objects[$hash]))
		{
			$output[] = "{\n$space$s*RECURSION*\n$space}";
		}
		elseif ($level < $limit)
		{
			$output[] = "<code>{";

			$objects[$hash] = TRUE;
			foreach ($array as $key => & $val)
			{
				if ($key[0] === "\x00")
				{
					// Determine if the access is protected or protected
					$access = '<small>'.(($key[1] === '*') ? 'protected' : 'private').'</small>';

					// Remove the access level from the variable name
					$key = substr($key, strrpos($key, "\x00") + 1);
				}
				else
				{
					$access = '<small>public</small>';
				}

				$output[] = "$space$s$access $key => ".Debug::_dump($val, $length, $limit, $level + 1);
			}
			unset($objects[$hash]);

			$output[] = "$space}</code>";
		}
		else
		{
			// Depth too great
			$output[] = "{\n$space$s...\n$space}";
		}

		return '<small>object</small> <span>'.get_class($var).'('.count($array).')</span> '.implode("\n", $output);
	}
	else
	{
		return '<small>'.gettype($var).'</small> '.htmlspecialchars(print_r($var, TRUE), ENT_NOQUOTES, Kohana::$charset);
	}
}