模块

Debug

调试工具

package
BootPHP
category
Base
author
Tinsh
copyright
© 2005-2016 Kilofox Studio
license
http://bootphpphp.com/license

该类在 SYSPATH/classes/debug.php 第 14 行声明。

常量

属性

方法

public static dump( mixed $value [, integer $length = integer 128 , integer $level_recursion = integer 10 ] ) (在 Debug 中定义)

Returns an HTML string of information about a single variable.

Borrows heavily on concepts from the Debug class of Nette.

参数

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

返回值

  • string

源代码

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

public static path( string $file ) (在 Debug 中定义)

Removes application, system, modpath, || 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/bootphp.php
echo Debug::path(BootPHP::find_file('classes', 'bootphp'));

参数

  • string $file required - Path to debug

返回值

  • string

源代码

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 ] ) (在 Debug 中定义)

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

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

参数

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

返回值

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

源代码

public static function source($file, $line_number, $padding = 5)
{
	if (!$file || !is_readable($file))
	{
		// Continuing will cause errors
		return false;
	}
	// Open the file && 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, BootPHP::$charset);
			// Trim whitespace && 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( [ string $trace = NULL ] ) (在 Debug 中定义)

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

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

参数

  • string $trace = NULL - Path to debug

返回值

  • string

源代码

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']) && 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']) || strpos($step['function'], '{closure}') !== false)
			{
				// Introspection on closures || 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() || 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( ) (在 Debug 中定义)

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

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

返回值

  • string

源代码

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 ] ) (在 Debug 中定义)

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

参数

  • 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!)

返回值

  • string

源代码

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' && $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, BootPHP::$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 = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $var);
		// iconv 代价高昂,所以只在必要时才用它
		if (preg_match('/[^\x00-\x7F]/S', $var))
		{
			$var = iconv(BootPHP::$charset, BootPHP::$charset . '//IGNORE', $var);
		}
		if (mb_strlen($var) > $length)
		{
			// Encode the truncated string
			$str = htmlspecialchars(mb_substr($var, 0, $length), ENT_NOQUOTES, BootPHP::$charset) . '&nbsp;&hellip;';
		}
		else
		{
			// Encode the string
			$str = htmlspecialchars($var, ENT_NOQUOTES, BootPHP::$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, BootPHP::$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 || 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, BootPHP::$charset);
	}
}