1: <?php
2: /**
3: * PHP Token Reflection
4: *
5: * Version 1.3.1
6: *
7: * LICENSE
8: *
9: * This source file is subject to the new BSD license that is bundled
10: * with this library in the file LICENSE.
11: *
12: * @author Ondřej Nešpor
13: * @author Jaroslav Hanslík
14: */
15:
16: namespace TokenReflection;
17:
18: use TokenReflection\Exception, TokenReflection\Stream\StreamBase as Stream;
19:
20: /**
21: * Basic abstract TokenReflection class.
22: *
23: * A common ancestor of ReflectionElement and ReflectionFile.
24: */
25: abstract class ReflectionBase implements IReflection
26: {
27: /**
28: * Class method cache.
29: *
30: * @var array
31: */
32: private static $methodCache = array();
33:
34: /**
35: * Object name (FQN).
36: *
37: * @var string
38: */
39: protected $name;
40:
41: /**
42: * Docblock definition.
43: *
44: * @var \TokenReflection\ReflectionAnnotation|boolean
45: */
46: protected $docComment;
47:
48: /**
49: * Parsed docblock definition.
50: *
51: * @var array
52: */
53: private $parsedDocComment;
54:
55: /**
56: * Reflection broker.
57: *
58: * @var \TokenReflection\Broker
59: */
60: private $broker;
61:
62: /**
63: * Constructor.
64: *
65: * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
66: * @param \TokenReflection\Broker $broker Reflection broker
67: * @param \TokenReflection\IReflection $parent Parent reflection object
68: */
69: public function __construct(Stream $tokenStream, Broker $broker, IReflection $parent = null)
70: {
71: $this->broker = $broker;
72:
73: $this->parseStream($tokenStream, $parent);
74: }
75:
76: /**
77: * Parses the token substream.
78: *
79: * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
80: * @param \TokenReflection\IReflection $parent Parent reflection object
81: */
82: abstract protected function parseStream(Stream $tokenStream, IReflection $parent = null);
83:
84: /**
85: * Returns the name (FQN).
86: *
87: * @return string
88: */
89: public function getName()
90: {
91: return $this->name;
92: }
93:
94: /**
95: * Returns the appropriate docblock definition.
96: *
97: * @return string|boolean
98: */
99: public function getDocComment()
100: {
101: return $this->docComment->getDocComment();
102: }
103:
104: /**
105: * Checks if there is a particular annotation.
106: *
107: * @param string $name Annotation name
108: * @return boolean
109: */
110: final public function hasAnnotation($name)
111: {
112: return $this->docComment->hasAnnotation($name);
113: }
114:
115: /**
116: * Returns a particular annotation value.
117: *
118: * @param string $name Annotation name
119: * @return string|array|null
120: */
121: final public function getAnnotation($name)
122: {
123: return $this->docComment->getAnnotation($name);
124: }
125:
126: /**
127: * Returns all annotations.
128: *
129: * @return array
130: */
131: final public function getAnnotations()
132: {
133: return $this->docComment->getAnnotations();
134: }
135:
136: /**
137: * Returns the reflection broker used by this reflection object.
138: *
139: * @return \TokenReflection\Broker
140: */
141: public function getBroker()
142: {
143: return $this->broker;
144: }
145:
146: /**
147: * Returns if the reflection object is internal.
148: *
149: * Always returns false - everything is user defined.
150: *
151: * @return boolean
152: */
153: public function isInternal()
154: {
155: return false;
156: }
157:
158: /**
159: * Returns if the reflection object is user defined.
160: *
161: * Always returns true - everything is user defined.
162: *
163: * @return boolean
164: */
165: public function isUserDefined()
166: {
167: return true;
168: }
169:
170: /**
171: * Returns if the current reflection comes from a tokenized source.
172: *
173: * @return boolean
174: */
175: public function isTokenized()
176: {
177: return true;
178: }
179:
180: /**
181: * Returns if the reflection subject is deprecated.
182: *
183: * @return boolean
184: */
185: public function isDeprecated()
186: {
187: return $this->hasAnnotation('deprecated');
188: }
189:
190: /**
191: * Returns the appropriate source code part.
192: *
193: * @return string
194: */
195: abstract public function getSource();
196:
197: /**
198: * Returns an element pretty (docblock compatible) name.
199: *
200: * @return string
201: */
202: public function getPrettyName()
203: {
204: return $this->name;
205: }
206:
207: /**
208: * Magic __get method.
209: *
210: * @param string $key Variable name
211: * @return mixed
212: */
213: final public function __get($key)
214: {
215: return self::get($this, $key);
216: }
217:
218: /**
219: * Magic __isset method.
220: *
221: * @param string $key Variable name
222: * @return boolean
223: */
224: final public function __isset($key)
225: {
226: return self::exists($this, $key);
227: }
228:
229: /**
230: * Magic __get method helper.
231: *
232: * @param \TokenReflection\IReflection $object Reflection object
233: * @param string $key Variable name
234: * @return mixed
235: * @throws \TokenReflection\Exception\RuntimeException If the requested parameter does not exist.
236: */
237: final public static function get(IReflection $object, $key)
238: {
239: if (!empty($key)) {
240: $className = get_class($object);
241: if (!isset(self::$methodCache[$className])) {
242: self::$methodCache[$className] = array_flip(get_class_methods($className));
243: }
244:
245: $methods = self::$methodCache[$className];
246: $key2 = ucfirst($key);
247: if (isset($methods['get' . $key2])) {
248: return $object->{'get' . $key2}();
249: } elseif (isset($methods['is' . $key2])) {
250: return $object->{'is' . $key2}();
251: }
252: }
253:
254: throw new Exception\RuntimeException(sprintf('Cannot read property "%s".', $key), Exception\RuntimeException::DOES_NOT_EXIST);
255: }
256:
257: /**
258: * Magic __isset method helper.
259: *
260: * @param \TokenReflection\IReflection $object Reflection object
261: * @param string $key Variable name
262: * @return boolean
263: */
264: final public static function exists(IReflection $object, $key)
265: {
266: try {
267: self::get($object, $key);
268: return true;
269: } catch (RuntimeException $e) {
270: return false;
271: }
272: }
273: }
274: