bkdotcom/PHPDebugConsole

View on GitHub
src/Debug/Plugin/Method/Trace.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

/**
 * This file is part of PHPDebugConsole
 *
 * @package   PHPDebugConsole
 * @author    Brad Kent <bkfake-github@yahoo.com>
 * @license   http://opensource.org/licenses/MIT MIT
 * @copyright 2014-2024 Brad Kent
 * @version   v3.1
 */

namespace bdk\Debug\Plugin\Method;

use bdk\Backtrace;
use bdk\Debug;
use bdk\Debug\LogEntry;
use bdk\Debug\Plugin\CustomMethodTrait;
use bdk\PubSub\SubscriberInterface;

/**
 * Trace method
 */
class Trace implements SubscriberInterface
{
    use CustomMethodTrait;

    /** @var string[] */
    protected $methods = array(
        'trace',
    );

    /**
     * Constructor
     *
     * @codeCoverageIgnore
     */
    public function __construct()
    {
    }

    /**
     * Log a stack trace
     *
     * Essentially PHP's `debug_backtrace()`, but displayed as a table
     *
     * @param bool   $inclContext Include code snippet
     * @param string $caption     (optional) Specify caption for the trace table
     *
     * @return Debug
     */
    public function trace($inclContext = false, $caption = 'trace')
    {
        if (!$this->debug->getCfg('collect', Debug::CONFIG_DEBUG)) {
            return $this->debug;
        }
        $logEntry = new LogEntry(
            $this->debug,
            __FUNCTION__,
            \func_get_args(),
            array(),
            $this->debug->rootInstance->getMethodDefaultArgs(__METHOD__),
            array(
                'caption',
                'inclContext',
            )
        );
        $this->doTrace($logEntry);
        $this->debug->log($logEntry);
        return $this->debug;
    }

    /**
     * Handle trace()
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return void
     */
    public function doTrace(LogEntry $logEntry)
    {
        $this->debug = $logEntry->getSubject();
        $meta = $this->getMeta($logEntry);
        $trace = isset($meta['trace'])
            ? $meta['trace']
            : $this->debug->backtrace->get($meta['inclArgs'] ? Backtrace::INCL_ARGS : 0);
        if ($trace && $meta['inclContext']) {
            $trace = $this->debug->backtrace->addContext($trace);
            $this->debug->addPlugin($this->debug->pluginHighlight, 'highlight');
        }
        unset($meta['trace']);
        $logEntry['args'] = array($trace);
        $logEntry['meta'] = $meta;
        $this->evalRows($logEntry);
        $this->debug->rootInstance->getPlugin('methodTable')->doTable($logEntry);
    }

    /**
     * Set default meta values
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return array meta values
     */
    private function getMeta(LogEntry $logEntry)
    {
        $meta = \array_merge(array(
            'caption' => 'trace',
            'columns' => array('file','line','function'),
            'detectFiles' => true,
            'inclArgs' => null,  // incl arguments with context?
                                 // will default to $inclContext
                                 //   may want to set meta['cfg']['objectsExclude'] = '*'
            'inclContext' => false,
            'sortable' => false,
            'trace' => null,  // set to specify trace
        ), $logEntry['meta']);

        if (\is_string($meta['caption']) === false) {
            $this->debug->warn(\sprintf(
                'trace caption should be a string.  %s provided',
                $this->debug->php->getDebugType($meta['caption'])
            ));
            $meta['caption'] = 'trace';
        }
        if ($meta['inclArgs'] === null) {
            $meta['inclArgs'] = $meta['inclContext'];
        }
        return $meta;
    }

    /**
     * Handle "eval()'d code" frames
     *
     * @param LogEntry $logEntry LogEntry instance
     *
     * @return void
     */
    private function evalRows(LogEntry $logEntry)
    {
        $meta = \array_replace_recursive(array(
            'tableInfo' => array(
                'rows' => array(),
            ),
        ), $logEntry['meta']);
        $trace = $logEntry['args'][0];
        foreach ($trace as $i => $frame) {
            if (!empty($frame['evalLine'])) {
                $meta['tableInfo']['rows'][$i]['attribs'] = array(
                    'data-file' => $frame['file'],
                    'data-line' => $frame['line'],
                );
                $trace[$i]['file'] = 'eval()\'d code';
                $trace[$i]['line'] = $frame['evalLine'];
            }
        }
        $logEntry['meta'] = $meta;
        $logEntry['args'] = array($trace);
    }
}