Viewing file: Frame.php (8.02 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */
namespace Whoops\Exception;
use InvalidArgumentException; use Serializable;
class Frame implements Serializable { /** * @var array */ protected $frame;
/** * @var string */ protected $fileContentsCache;
/** * @var array[] */ protected $comments = [];
/** * @var bool */ protected $application;
/** * @param array[] */ public function __construct(array $frame) { $this->frame = $frame; }
/** * @param bool $shortened * @return string|null */ public function getFile($shortened = false) { if (empty($this->frame['file'])) { return null; }
$file = $this->frame['file'];
// Check if this frame occurred within an eval(). // @todo: This can be made more reliable by checking if we've entered // eval() in a previous trace, but will need some more work on the upper // trace collector(s). if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) { $file = $this->frame['file'] = $matches[1]; $this->frame['line'] = (int) $matches[2]; }
if ($shortened && is_string($file)) { // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks. $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); if ($dirname !== '/') { $file = str_replace($dirname, "…", $file); } $file = str_replace("/", "/­", $file); }
return $file; }
/** * @return int|null */ public function getLine() { return isset($this->frame['line']) ? $this->frame['line'] : null; }
/** * @return string|null */ public function getClass() { return isset($this->frame['class']) ? $this->frame['class'] : null; }
/** * @return string|null */ public function getFunction() { return isset($this->frame['function']) ? $this->frame['function'] : null; }
/** * @return array */ public function getArgs() { return isset($this->frame['args']) ? (array) $this->frame['args'] : []; }
/** * Returns the full contents of the file for this frame, * if it's known. * @return string|null */ public function getFileContents() { if ($this->fileContentsCache === null && $filePath = $this->getFile()) { // Leave the stage early when 'Unknown' or '[internal]' is passed // this would otherwise raise an exception when // open_basedir is enabled. if ($filePath === "Unknown" || $filePath === '[internal]') { return null; }
try { $this->fileContentsCache = file_get_contents($filePath); } catch (ErrorException $exception) { // Internal file paths of PHP extensions cannot be opened } }
return $this->fileContentsCache; }
/** * Adds a comment to this frame, that can be received and * used by other handlers. For example, the PrettyPage handler * can attach these comments under the code for each frame. * * An interesting use for this would be, for example, code analysis * & annotations. * * @param string $comment * @param string $context Optional string identifying the origin of the comment */ public function addComment($comment, $context = 'global') { $this->comments[] = [ 'comment' => $comment, 'context' => $context, ]; }
/** * Returns all comments for this frame. Optionally allows * a filter to only retrieve comments from a specific * context. * * @param string $filter * @return array[] */ public function getComments($filter = null) { $comments = $this->comments;
if ($filter !== null) { $comments = array_filter($comments, function ($c) use ($filter) { return $c['context'] == $filter; }); }
return $comments; }
/** * Returns the array containing the raw frame data from which * this Frame object was built * * @return array */ public function getRawFrame() { return $this->frame; }
/** * Returns the contents of the file for this frame as an * array of lines, and optionally as a clamped range of lines. * * NOTE: lines are 0-indexed * * @example * Get all lines for this file * $frame->getFileLines(); // => array( 0 => '<?php', 1 => '...', ...) * @example * Get one line for this file, starting at line 10 (zero-indexed, remember!) * $frame->getFileLines(9, 1); // array( 9 => '...' ) * * @throws InvalidArgumentException if $length is less than or equal to 0 * @param int $start * @param int $length * @return string[]|null */ public function getFileLines($start = 0, $length = null) { if (null !== ($contents = $this->getFileContents())) { $lines = explode("\n", $contents);
// Get a subset of lines from $start to $end if ($length !== null) { $start = (int) $start; $length = (int) $length; if ($start < 0) { $start = 0; }
if ($length <= 0) { throw new InvalidArgumentException( "\$length($length) cannot be lower or equal to 0" ); }
$lines = array_slice($lines, $start, $length, true); }
return $lines; } }
/** * Implements the Serializable interface, with special * steps to also save the existing comments. * * @see Serializable::serialize * @return string */ public function serialize() { $frame = $this->frame; if (!empty($this->comments)) { $frame['_comments'] = $this->comments; }
return serialize($frame); }
public function __serialize() { $frame = $this->frame; if (!empty($this->comments)) { $frame['_comments'] = $this->comments; } return $frame; }
/** * Unserializes the frame data, while also preserving * any existing comment data. * * @see Serializable::unserialize * @param string $serializedFrame */ public function unserialize($serializedFrame) { $frame = unserialize($serializedFrame);
if (!empty($frame['_comments'])) { $this->comments = $frame['_comments']; unset($frame['_comments']); }
$this->frame = $frame; }
public function __unserialize($frame) { if (!empty($frame['_comments'])) { $this->comments = $frame['_comments']; unset($frame['_comments']); }
$this->frame = $frame; }
/** * Compares Frame against one another * @param Frame $frame * @return bool */ public function equals(Frame $frame) { if (!$this->getFile() || $this->getFile() === 'Unknown' || !$this->getLine()) { return false; } return $frame->getFile() === $this->getFile() && $frame->getLine() === $this->getLine(); }
/** * Returns whether this frame belongs to the application or not. * * @return boolean */ public function isApplication() { return $this->application; }
/** * Mark as an frame belonging to the application. * * @param boolean $application */ public function setApplication($application) { $this->application = $application; } }
|