Modules

Debug
extends Kohana_Debug

Contains debugging and dumping tools.

package
Kohana
category
Base
author
Kohana Team
copyright
© 2008-2014 Kohana Team
license
https://kohana.top/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 = ['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 = ['include', 'include_once', 'require', 'require_once'];

    $output = [];
    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 = [];
            } else {
                // Sanitize the file path
                $args = [$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 = [];

            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[] = [
            '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 = [];
    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 = [];

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

        static $marker;

        if ($marker === null) {
            // Make a unique marker - force it to be alphanumeric so that it is always treated as a string array key
            $marker = uniqid("\x00") . "x";
        }

        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 = [];

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

        $hash = spl_object_hash($var);

        // Objects that are being dumped
        static $objects = [];

        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);
    }
}