1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: namespace TokenReflection;
17:
18: use TokenReflection\Exception, TokenReflection\Stream\StreamBase as Stream;
19:
20: 21: 22: 23: 24:
25: abstract class ReflectionElement extends ReflectionBase
26: {
27: 28: 29: 30: 31:
32: const DOCBLOCK_TEMPLATE_START = '/**#@+';
33:
34: 35: 36: 37: 38:
39: const DOCBLOCK_TEMPLATE_END = '/**#@-*/';
40:
41: 42: 43: 44: 45:
46: private static $methodCache = array();
47:
48: 49: 50: 51: 52:
53: private $fileName;
54:
55: 56: 57: 58: 59:
60: private $startLine;
61:
62: 63: 64: 65: 66:
67: private $endLine;
68:
69: 70: 71: 72: 73:
74: protected $startPosition;
75:
76: 77: 78: 79: 80:
81: private $endPosition;
82:
83: 84: 85: 86: 87:
88: protected $docblockTemplates = array();
89:
90: 91: 92: 93: 94: 95: 96: 97:
98: final public function __construct(Stream $tokenStream, Broker $broker, IReflection $parent = null)
99: {
100: if (0 === $tokenStream->count()) {
101: throw new Exception\ParseException($this, $tokenStream, 'Reflection token stream must not be empty.', Exception\ParseException::INVALID_ARGUMENT);
102: }
103:
104: parent::__construct($tokenStream, $broker, $parent);
105: }
106:
107: 108: 109: 110: 111: 112:
113: final protected function parseStream(Stream $tokenStream, IReflection $parent = null)
114: {
115: $this->fileName = $tokenStream->getFileName();
116:
117: $this
118: ->processParent($parent, $tokenStream)
119: ->parseStartLine($tokenStream)
120: ->parseDocComment($tokenStream, $parent)
121: ->parse($tokenStream, $parent)
122: ->parseChildren($tokenStream, $parent)
123: ->parseEndLine($tokenStream);
124: }
125:
126: 127: 128: 129: 130:
131: public function getFileName()
132: {
133: return $this->fileName;
134: }
135:
136: 137: 138: 139: 140: 141:
142: public function getFileReflection()
143: {
144: return $this->getBroker()->getFile($this->fileName);
145: }
146:
147: 148: 149: 150: 151:
152: public function getStartLine()
153: {
154: return $this->startLine;
155: }
156:
157: 158: 159: 160: 161:
162: public function getEndLine()
163: {
164: return $this->endLine;
165: }
166:
167: 168: 169: 170: 171: 172: 173:
174: public function getExtension()
175: {
176: return null;
177: }
178:
179: 180: 181: 182: 183: 184: 185:
186: public function getExtensionName()
187: {
188: return false;
189: }
190:
191: 192: 193: 194: 195:
196: public function getSource()
197: {
198: return $this->broker->getFileTokens($this->getFileName())->getSourcePart($this->startPosition, $this->endPosition);
199: }
200:
201: 202: 203: 204: 205:
206: public function getStartPosition()
207: {
208: return $this->startPosition;
209: }
210:
211: 212: 213: 214: 215:
216: public function getEndPosition()
217: {
218: return $this->endPosition;
219: }
220:
221: 222: 223: 224: 225:
226: protected function getDocblockTemplates()
227: {
228: return $this->docblockTemplates;
229: }
230:
231: 232: 233: 234: 235: 236: 237:
238: protected function processParent(IReflection $parent, Stream $tokenStream)
239: {
240:
241: return $this;
242: }
243:
244: 245: 246: 247: 248: 249: 250:
251: protected function (Stream $tokenStream, IReflection $parent)
252: {
253: if ($this instanceof ReflectionParameter) {
254: $this->docComment = new ReflectionAnnotation($this);
255: return $this;
256: }
257:
258: $position = $tokenStream->key();
259:
260: if ($tokenStream->is(T_DOC_COMMENT, $position - 1)) {
261: $value = $tokenStream->getTokenValue($position - 1);
262: if (self::DOCBLOCK_TEMPLATE_END !== $value) {
263: $this->docComment = new ReflectionAnnotation($this, $value);
264: $this->startPosition--;
265: }
266: } elseif ($tokenStream->is(T_DOC_COMMENT, $position - 2)) {
267: $value = $tokenStream->getTokenValue($position - 2);
268: if (self::DOCBLOCK_TEMPLATE_END !== $value) {
269: $this->docComment = new ReflectionAnnotation($this, $value);
270: $this->startPosition -= 2;
271: }
272: } elseif ($tokenStream->is(T_COMMENT, $position - 1) && preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $tokenStream->getTokenValue($position - 1))) {
273: $this->docComment = new ReflectionAnnotation($this, $tokenStream->getTokenValue($position - 1));
274: $this->startPosition--;
275: } elseif ($tokenStream->is(T_COMMENT, $position - 2) && preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $tokenStream->getTokenValue($position - 2))) {
276: $this->docComment = new ReflectionAnnotation($this, $tokenStream->getTokenValue($position - 2));
277: $this->startPosition -= 2;
278: }
279:
280: if (null === $this->docComment) {
281: $this->docComment = new ReflectionAnnotation($this);
282: }
283:
284: if ($parent instanceof ReflectionElement) {
285: $this->docComment->setTemplates($parent->getDocblockTemplates());
286: }
287:
288: return $this;
289: }
290:
291: 292: 293: 294: 295: 296:
297: private final function parseStartLine(Stream $tokenStream)
298: {
299: $token = $tokenStream->current();
300: $this->startLine = $token[2];
301:
302: $this->startPosition = $tokenStream->key();
303:
304: return $this;
305: }
306:
307: 308: 309: 310: 311: 312:
313: private final function parseEndLine(Stream $tokenStream)
314: {
315: $token = $tokenStream->current();
316: $this->endLine = $token[2];
317:
318: $this->endPosition = $tokenStream->key();
319:
320: return $this;
321: }
322:
323: 324: 325: 326: 327: 328: 329:
330: abstract protected function parse(Stream $tokenStream, IReflection $parent);
331:
332: 333: 334: 335: 336: 337:
338: abstract protected function parseName(Stream $tokenStream);
339:
340: 341: 342: 343: 344: 345: 346:
347: protected function parseChildren(Stream $tokenStream, IReflection $parent)
348: {
349:
350: return $this;
351: }
352: }
353: