1 | <?php |
||
12 | class Frame implements Serializable |
||
13 | { |
||
14 | /** |
||
15 | * @var array |
||
16 | */ |
||
17 | protected $frame; |
||
18 | |||
19 | /** |
||
20 | * @var string |
||
21 | */ |
||
22 | protected $fileContentsCache; |
||
23 | |||
24 | /** |
||
25 | * @var array[] |
||
26 | */ |
||
27 | protected $comments = array(); |
||
28 | |||
29 | /** |
||
30 | * @param array[] |
||
31 | */ |
||
32 | 1 | public function __construct(array $frame) |
|
33 | { |
||
34 | 1 | $this->frame = $frame; |
|
35 | 1 | } |
|
36 | |||
37 | /** |
||
38 | * @param bool $shortened |
||
39 | * @return string|null |
||
40 | */ |
||
41 | 2 | public function getFile($shortened = false) |
|
42 | { |
||
43 | 2 | if (empty($this->frame['file'])) { |
|
44 | 1 | return null; |
|
45 | } |
||
46 | |||
47 | 2 | $file = $this->frame['file']; |
|
48 | |||
49 | // Check if this frame occurred within an eval(). |
||
50 | // @todo: This can be made more reliable by checking if we've entered |
||
51 | // eval() in a previous trace, but will need some more work on the upper |
||
52 | // trace collector(s). |
||
53 | 2 | if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) { |
|
54 | $file = $this->frame['file'] = $matches[1]; |
||
55 | $this->frame['line'] = (int) $matches[2]; |
||
56 | } |
||
57 | |||
58 | 2 | if ($shortened && is_string($file)) { |
|
59 | // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks. |
||
60 | $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); |
||
61 | $file = str_replace($dirname, "…", $file); |
||
62 | $file = str_replace("/", "/­", $file); |
||
63 | } |
||
64 | |||
65 | 2 | return $file; |
|
66 | } |
||
67 | |||
68 | /** |
||
69 | * @return int|null |
||
70 | */ |
||
71 | 2 | public function getLine() |
|
72 | { |
||
73 | 2 | return isset($this->frame['line']) ? $this->frame['line'] : null; |
|
74 | } |
||
75 | |||
76 | /** |
||
77 | * @return string|null |
||
78 | */ |
||
79 | 2 | public function getClass() |
|
80 | { |
||
81 | 2 | return isset($this->frame['class']) ? $this->frame['class'] : null; |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * @return string|null |
||
86 | */ |
||
87 | 2 | public function getFunction() |
|
88 | { |
||
89 | 2 | return isset($this->frame['function']) ? $this->frame['function'] : null; |
|
90 | } |
||
91 | |||
92 | /** |
||
93 | * @return array |
||
94 | */ |
||
95 | 1 | public function getArgs() |
|
96 | { |
||
97 | 1 | return isset($this->frame['args']) ? (array) $this->frame['args'] : array(); |
|
98 | } |
||
99 | |||
100 | /** |
||
101 | * Returns the full contents of the file for this frame, |
||
102 | * if it's known. |
||
103 | * @return string|null |
||
104 | */ |
||
105 | 1 | public function getFileContents() |
|
106 | { |
||
107 | 1 | if ($this->fileContentsCache === null && $filePath = $this->getFile()) { |
|
108 | // Leave the stage early when 'Unknown' is passed |
||
109 | // this would otherwise raise an exception when |
||
110 | // open_basedir is enabled. |
||
111 | 1 | if ($filePath === "Unknown") { |
|
112 | return null; |
||
113 | } |
||
114 | |||
115 | // Return null if the file doesn't actually exist. |
||
116 | 1 | if (!is_file($filePath)) { |
|
117 | return null; |
||
118 | } |
||
119 | |||
120 | 1 | $this->fileContentsCache = file_get_contents($filePath); |
|
121 | 1 | } |
|
122 | |||
123 | 1 | return $this->fileContentsCache; |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * Adds a comment to this frame, that can be received and |
||
128 | * used by other handlers. For example, the PrettyPage handler |
||
129 | * can attach these comments under the code for each frame. |
||
130 | * |
||
131 | * An interesting use for this would be, for example, code analysis |
||
132 | * & annotations. |
||
133 | * |
||
134 | * @param string $comment |
||
135 | * @param string $context Optional string identifying the origin of the comment |
||
136 | */ |
||
137 | 2 | public function addComment($comment, $context = 'global') |
|
138 | { |
||
139 | 2 | $this->comments[] = array( |
|
140 | 2 | 'comment' => $comment, |
|
141 | 2 | 'context' => $context, |
|
142 | ); |
||
143 | 2 | } |
|
144 | |||
145 | /** |
||
146 | * Returns all comments for this frame. Optionally allows |
||
147 | * a filter to only retrieve comments from a specific |
||
148 | * context. |
||
149 | * |
||
150 | * @param string $filter |
||
151 | * @return array[] |
||
152 | */ |
||
153 | 2 | public function getComments($filter = null) |
|
165 | |||
166 | /** |
||
167 | * Returns the array containing the raw frame data from which |
||
168 | * this Frame object was built |
||
169 | * |
||
170 | * @return array |
||
171 | */ |
||
172 | public function getRawFrame() |
||
173 | { |
||
174 | return $this->frame; |
||
175 | } |
||
176 | |||
177 | /** |
||
178 | * Returns the contents of the file for this frame as an |
||
179 | * array of lines, and optionally as a clamped range of lines. |
||
180 | * |
||
181 | * NOTE: lines are 0-indexed |
||
182 | * |
||
183 | * @example |
||
184 | * Get all lines for this file |
||
185 | * $frame->getFileLines(); // => array( 0 => '<?php', 1 => '...', ...) |
||
186 | * @example |
||
187 | * Get one line for this file, starting at line 10 (zero-indexed, remember!) |
||
188 | * $frame->getFileLines(9, 1); // array( 10 => '...', 11 => '...') |
||
189 | * |
||
190 | * @throws InvalidArgumentException if $length is less than or equal to 0 |
||
191 | * @param int $start |
||
192 | * @param int $length |
||
193 | * @return string[]|null |
||
194 | */ |
||
195 | 2 | public function getFileLines($start = 0, $length = null) |
|
220 | |||
221 | /** |
||
222 | * Implements the Serializable interface, with special |
||
223 | * steps to also save the existing comments. |
||
224 | * |
||
225 | * @see Serializable::serialize |
||
226 | * @return string |
||
227 | */ |
||
228 | 1 | public function serialize() |
|
237 | |||
238 | /** |
||
239 | * Unserializes the frame data, while also preserving |
||
240 | * any existing comment data. |
||
241 | * |
||
242 | * @see Serializable::unserialize |
||
243 | * @param string $serializedFrame |
||
244 | */ |
||
245 | 1 | public function unserialize($serializedFrame) |
|
256 | |||
257 | /** |
||
258 | * Compares Frame against one another |
||
259 | * @param Frame $frame |
||
260 | * @return bool |
||
261 | */ |
||
262 | 1 | public function equals(Frame $frame) |
|
269 | } |
||
270 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: