Revision 148 | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?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;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 $endif ($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;}}