Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   1  <?php
   2  /**
   3   * Wrapper around backtraces providing utility methods.
   4   *
   5   * Copyright 1999-2017 Horde LLC (http://www.horde.org/)
   6   *
   7   * @category   Horde
   8   * @package    Support
   9   * @license    http://www.horde.org/licenses/bsd
  10   */
  11  class Horde_Support_Backtrace
  12  {
  13      /**
  14       * Backtrace.
  15       *
  16       * @var array
  17       */
  18      public $backtrace;
  19  
  20      /**
  21       * Constructor.
  22       *
  23       * @param Exception|array $backtrace  The backtrace source. Either a
  24       *                                    trowable, an exception or an existing
  25       *                                    backtrace.
  26       *                                    Defaults to the current stack.
  27       */
  28      public function __construct($backtrace = null)
  29      {
  30          if ($backtrace instanceof Throwable) {
  31              $this->createFromThrowable($backtrace);
  32          } elseif ($backtrace instanceof Exception) {
  33              $this->createFromException($backtrace);
  34          } elseif ($backtrace) {
  35              $this->createFromDebugBacktrace($backtrace);
  36          } else {
  37              $this->createFromDebugBacktrace(debug_backtrace(), 1);
  38          }
  39      }
  40  
  41      /**
  42       * Wraps the result of debug_backtrace().
  43       *
  44       * By specifying a non-zero $nestingLevel, levels of the backtrace can be
  45       * ignored. For instance, when Horde_Support_Backtrace creates a backtrace
  46       * for you, it ignores the Horde_Backtrace constructor in the wrapped
  47       * trace.
  48       *
  49       * @param array $backtrace       The debug_backtrace() result.
  50       * @param integer $nestingLevel  The number of levels of the backtrace to
  51       *                               ignore.
  52       */
  53      public function createFromDebugBacktrace($backtrace, $nestingLevel = 0)
  54      {
  55          while ($nestingLevel > 0) {
  56              array_shift($backtrace);
  57              --$nestingLevel;
  58          }
  59  
  60          $this->backtrace = $backtrace;
  61      }
  62  
  63      /**
  64       * Wraps an error object's backtrace.
  65       *
  66       * @since Horde_Support 2.2.0
  67       *
  68       * @param Throwable $e  The error to wrap.
  69       */
  70      public function createFromThrowable(Throwable $e)
  71      {
  72          $this->_createFromThrowable($e);
  73      }
  74  
  75      /**
  76       * Wraps an error object's backtrace.
  77       *
  78       * @todo Merge with createFromThrowable with PHP 7.
  79       *
  80       * @param Throwable $e  The error to wrap.
  81       */
  82      protected function _createFromThrowable($e)
  83      {
  84          $this->backtrace = $e->getTrace();
  85          if ($previous = $e->getPrevious()) {
  86              $backtrace = new self($previous);
  87              $this->backtrace = array_merge($backtrace->backtrace,
  88                                             $this->backtrace);
  89          }
  90      }
  91  
  92      /**
  93       * Wraps an Exception object's backtrace.
  94       *
  95       * @todo Remove with PHP 7.
  96       *
  97       * @param Exception $e  The exception to wrap.
  98       */
  99      public function createFromException(Exception $e)
 100      {
 101          $this->_createFromThrowable($e);
 102      }
 103  
 104      /**
 105       * Returns the nesting level (number of calls deep) of the current context.
 106       *
 107       * @return integer  Nesting level.
 108       */
 109      public function getNestingLevel()
 110      {
 111          return count($this->backtrace);
 112      }
 113  
 114      /**
 115       * Returns the context at a specific nesting level.
 116       *
 117       * @param integer $nestingLevel  0 == current level, 1 == caller, and so on
 118       *
 119       * @return array  The requested context.
 120       */
 121      public function getContext($nestingLevel)
 122      {
 123          if (!isset($this->backtrace[$nestingLevel])) {
 124              throw new Horde_Exception('Unknown nesting level');
 125          }
 126          return $this->backtrace[$nestingLevel];
 127      }
 128  
 129      /**
 130       * Returns details about the routine where the exception occurred.
 131       *
 132       * @return array $caller
 133       */
 134      public function getCurrentContext()
 135      {
 136          return $this->getContext(0);
 137      }
 138  
 139      /**
 140       * Returns details about the caller of the routine where the exception
 141       * occurred.
 142       *
 143       * @return array $caller
 144       */
 145      public function getCallingContext()
 146      {
 147          return $this->getContext(1);
 148      }
 149  
 150      /**
 151       * Returns a simple, human-readable list of the complete backtrace.
 152       *
 153       * @return string  The backtrace map.
 154       */
 155      public function __toString()
 156      {
 157          $count = count($this->backtrace);
 158          $pad = strlen($count);
 159          $map = '';
 160          for ($i = $count - 1; $i >= 0; $i--) {
 161              $map .= str_pad($count - $i, $pad, ' ', STR_PAD_LEFT) . '. ';
 162              if (isset($this->backtrace[$i]['class'])) {
 163                  $map .= $this->backtrace[$i]['class']
 164                      . $this->backtrace[$i]['type'];
 165              }
 166              $map .= $this->backtrace[$i]['function'] . '()';
 167              if (isset($this->backtrace[$i]['file'])) {
 168                  $map .= ' ' . $this->backtrace[$i]['file']
 169                      . ':' . $this->backtrace[$i]['line'];
 170              }
 171              $map .= "\n";
 172          }
 173          return $map;
 174      }
 175  }