1: <?php
2:
3: namespace PHPixie\Debug\Tracer\Trace;
4:
5: class Element
6: {
7: protected $dumper;
8: protected $file;
9: protected $line;
10: protected $class;
11: protected $functionName;
12: protected $args;
13: protected $lineContents;
14:
15: public function __construct(
16: $dumper,
17: $file = null,
18: $line = null,
19: $functionName = null,
20: $arguments = null,
21: $className = null,
22: $object = null,
23: $type = null
24: )
25: {
26: $this->dumper = $dumper;
27: $this->file = $file;
28: $this->line = $line;
29: $this->functionName = $functionName;
30: $this->arguments = $arguments;
31: $this->className = $className;
32: $this->object = $object;
33: $this->type = $type;
34: }
35:
36: public function file()
37: {
38: return $this->file;
39: }
40:
41: public function line($offset = 0)
42: {
43: if(!$this->lineAndFileAvailable()) {
44: return null;
45: }
46:
47: $line = $this->line + $offset;
48:
49: if($line < 1) {
50: throw new \PHPixie\Debug\Exception("Invalid negative offset '$offset', line number must be larger than 0");
51: }
52:
53: if($offset > 0) {
54: $this->requireLineContents();
55: $count = count($this->lineContents);
56: if($line > $count) {
57: throw new \PHPixie\Debug\Exception("Invalid offset '$offset', line number must not exceed line count {$count}");
58: }
59: }
60:
61: return $line;
62: }
63:
64: public function functionName()
65: {
66: return $this->functionName;
67: }
68:
69: public function arguments()
70: {
71: return $this->arguments;
72: }
73:
74: public function className()
75: {
76: return $this->className;
77: }
78:
79: public function object()
80: {
81: return $this->object;
82: }
83:
84: public function type()
85: {
86: return $this->type;
87: }
88:
89: public function shortArgumentDumps()
90: {
91: $dumps = array();
92: foreach($this->arguments as $argument) {
93: $dumps[]= $this->dumper->shortDump($argument);
94: }
95: return $dumps;
96: }
97:
98: public function lineContents($offset = 0)
99: {
100: if(!$this->lineAndFileAvailable()) {
101: return null;
102: }
103:
104: $this->requireLineContents();
105: $line = $this->line($offset);
106: return rtrim($this->lineContents[$line-1], "\n\r");
107: }
108:
109: public function context($withArguments = false)
110: {
111: if($this->functionName === null) {
112: return null;
113: }
114:
115: if($this->className !== null) {
116: $context = $this->className.$this->type.$this->functionName;
117:
118: }else{
119: $context = $this->functionName;
120: }
121:
122: if($withArguments) {
123: $shortArgumentDumps = $this->shortArgumentDumps();
124: $context.='('.implode(', ', $shortArgumentDumps).')';
125: }
126:
127: return $context;
128: }
129:
130: public function getNeighboringOffsets($limit)
131: {
132: $offsets = $this->getNeighboringLines($limit);
133: foreach($offsets as $key => $line) {
134: $offsets[$key] = $line - $this->line;
135: }
136:
137: return $offsets;
138: }
139:
140: protected function getNeighboringLines($limit)
141: {
142: if(!$this->lineAndFileAvailable()) {
143: return array();
144: }
145:
146: $this->requireLineContents();
147: $count = count($this->lineContents);
148:
149: if($limit > $count) {
150: return range(1 , $count);
151: }
152:
153: $start = $this->line - (int) ($limit/2);
154:
155: if($start < 1) {
156: return range(1, $limit);
157: }
158:
159: if($start + $limit - 1 > $count) {
160:
161: return range($count - $limit + 1, $count);
162: }
163:
164: $end = $start + $limit - 1;
165:
166: if($start > $end) {
167: return array();
168: }
169:
170: return range($start, $start + $limit - 1);
171: }
172:
173: public function asString($withArguments = true, $withContext = true)
174: {
175: $string = $this->location();
176:
177: if($withContext) {
178: $context = $this->context($withArguments);
179: if($context !== null) {
180: $string.= "\n ".$context;
181: }
182: }
183:
184: return $string;
185: }
186:
187: public function location()
188: {
189: if($this->file !== null) {
190: $string = $this->file;
191: }else{
192: $string = '<unknown>';
193: }
194:
195: if($this->line !== null) {
196: $string.= ':'.$this->line;
197: }
198:
199: return $string;
200: }
201:
202: public function __toString()
203: {
204: return $this->asString();
205: }
206:
207: protected function lineAndFileAvailable()
208: {
209: return $this->line !== null && $this->file !== null;
210: }
211:
212: protected function requireLineContents()
213: {
214: if($this->lineContents === null) {
215: $this->lineContents = file($this->file);
216: }
217: }
218:
219: }