1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: namespace TokenReflection;
17:
18: 19: 20:
21: class Resolver
22: {
23: 24: 25: 26: 27:
28: const CONSTANT_NOT_FOUND = '~~NOT RESOLVED~~';
29:
30: 31: 32: 33: 34: 35: 36:
37: final public function __construct()
38: {
39: throw new \LogicException('Static class cannot be instantiated.');
40: }
41:
42: 43: 44: 45: 46: 47: 48: 49:
50: final public static function resolveClassFQN($className, array $aliases, $namespaceName = null)
51: {
52: if ($className{0} == '\\') {
53:
54: return ltrim($className, '\\');
55: }
56:
57: if (false === ($position = strpos($className, '\\'))) {
58:
59: if (isset($aliases[$className])) {
60: return $aliases[$className];
61: }
62: } else {
63:
64: $alias = substr($className, 0, $position);
65: if (isset($aliases[$alias])) {
66: return $aliases[$alias] . '\\' . substr($className, $position + 1);
67: }
68: }
69:
70: return null === $namespaceName || '' === $namespaceName || $namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME ? $className : $namespaceName . '\\' . $className;
71: }
72:
73: 74: 75: 76: 77: 78: 79: 80: 81:
82: final public static function getValueDefinition(array $tokens, ReflectionElement $reflection)
83: {
84: if ($reflection instanceof ReflectionConstant || $reflection instanceof ReflectionFunction) {
85: $namespace = $reflection->getNamespaceName();
86: } elseif ($reflection instanceof ReflectionParameter) {
87: $namespace = $reflection->getDeclaringFunction()->getNamespaceName();
88: } elseif ($reflection instanceof ReflectionProperty || $reflection instanceof ReflectionMethod) {
89: $namespace = $reflection->getDeclaringClass()->getNamespaceName();
90: } else {
91: throw new Exception\RuntimeException('Invalid reflection object given.', Exception\RuntimeException::INVALID_ARGUMENT, $reflection);
92: }
93:
94:
95: foreach ($tokens as $index => $token) {
96: if (T_LINE === $token[0]) {
97: $tokens[$index] = array(
98: T_LNUMBER,
99: $token[2],
100: $token[2]
101: );
102: }
103: }
104:
105: $source = self::getSourceCode($tokens);
106:
107: $constants = self::findConstants($tokens, $reflection);
108: if (!empty($constants)) {
109: foreach (array_reverse($constants, true) as $offset => $constant) {
110: $value = '';
111:
112: try {
113: switch ($constant) {
114: case '__LINE__':
115: throw new Exception\RuntimeException('__LINE__ constant cannot be resolved this way.', Exception\RuntimeException::UNSUPPORTED, $reflection);
116: case '__FILE__':
117: $value = $reflection->getFileName();
118: break;
119: case '__DIR__':
120: $value = dirname($reflection->getFileName());
121: break;
122: case '__FUNCTION__':
123: if ($reflection instanceof IReflectionParameter) {
124: $value = $reflection->getDeclaringFunctionName();
125: } elseif ($reflection instanceof IReflectionFunctionBase) {
126: $value = $reflection->getName();
127: }
128: break;
129: case '__CLASS__':
130: if ($reflection instanceof IReflectionConstant || $reflection instanceof IReflectionParameter || $reflection instanceof IReflectionProperty || $reflection instanceof IReflectionMethod) {
131: $value = $reflection->getDeclaringClassName() ?: '';
132: }
133: break;
134: case '__TRAIT__':
135: if ($reflection instanceof IReflectionMethod || $reflection instanceof IReflectionProperty) {
136: $value = $reflection->getDeclaringTraitName() ?: '';
137: } elseif ($reflection instanceof IReflectionParameter) {
138: $method = $reflection->getDeclaringFunction();
139: if ($method instanceof IReflectionMethod) {
140: $value = $method->getDeclaringTraitName() ?: '';
141: }
142: }
143: break;
144: case '__METHOD__':
145: if ($reflection instanceof IReflectionParameter) {
146: if (null !== $reflection->getDeclaringClassName()) {
147: $value = $reflection->getDeclaringClassName() . '::' . $reflection->getDeclaringFunctionName();
148: } else {
149: $value = $reflection->getDeclaringFunctionName();
150: }
151: } elseif ($reflection instanceof IReflectionConstant || $reflection instanceof IReflectionProperty) {
152: $value = $reflection->getDeclaringClassName() ?: '';
153: } elseif ($reflection instanceof IReflectionMethod) {
154: $value = $reflection->getDeclaringClassName() . '::' . $reflection->getName();
155: } elseif ($reflection instanceof IReflectionFunction) {
156: $value = $reflection->getName();
157: }
158: break;
159: case '__NAMESPACE__':
160: if (($reflection instanceof IReflectionConstant && null !== $reflection->getDeclaringClassName()) || $reflection instanceof IReflectionProperty) {
161: $value = $reflection->getDeclaringClass()->getNamespaceName();
162: } elseif ($reflection instanceof IReflectionParameter) {
163: if (null !== $reflection->getDeclaringClassName()) {
164: $value = $reflection->getDeclaringClass()->getNamespaceName();
165: } else {
166: $value = $reflection->getDeclaringFunction()->getNamespaceName();
167: }
168: } elseif ($reflection instanceof IReflectionMethod) {
169: $value = $reflection->getDeclaringClass()->getNamespaceName();
170: } else {
171: $value = $reflection->getNamespaceName();
172: }
173: break;
174: default:
175: if (0 === stripos($constant, 'self::') || 0 === stripos($constant, 'parent::')) {
176:
177:
178: if ($reflection instanceof ReflectionConstant) {
179: throw new Exception\RuntimeException('Constants cannot use self:: and parent:: references.', Exception\RuntimeException::UNSUPPORTED, $reflection);
180: } elseif ($reflection instanceof ReflectionParameter && null === $reflection->getDeclaringClassName()) {
181: throw new Exception\RuntimeException('Function parameters cannot use self:: and parent:: references.', Exception\RuntimeException::UNSUPPORTED, $reflection);
182: }
183:
184: if (0 === stripos($constant, 'self::')) {
185: $className = $reflection->getDeclaringClassName();
186: } else {
187: $declaringClass = $reflection->getDeclaringClass();
188: $className = $declaringClass->getParentClassName() ?: self::CONSTANT_NOT_FOUND;
189: }
190:
191: $constantName = $className . substr($constant, strpos($constant, '::'));
192: } else {
193: $constantName = self::resolveClassFQN($constant, $reflection->getNamespaceAliases(), $namespace);
194: if ($cnt = strspn($constant, '\\')) {
195: $constantName = str_repeat('\\', $cnt) . $constantName;
196: }
197: }
198:
199: $reflection = $reflection->getBroker()->getConstant($constantName);
200: $value = $reflection->getValue();
201: }
202: } catch (Exception\RuntimeException $e) {
203: $value = self::CONSTANT_NOT_FOUND;
204: }
205:
206: $source = substr_replace($source, var_export($value, true), $offset, strlen($constant));
207: }
208: }
209:
210: return self::evaluate(sprintf("return %s;\n", $source));
211: }
212:
213: 214: 215: 216: 217: 218:
219: final public static function getSourceCode(array $tokens)
220: {
221: if (empty($tokens)) {
222: return null;
223: }
224:
225: $source = '';
226: foreach ($tokens as $token) {
227: $source .= $token[1];
228: }
229: return $source;
230: }
231:
232: 233: 234: 235: 236: 237: 238:
239: final public static function findConstants(array $tokens, ReflectionElement $reflection)
240: {
241: static $accepted = array(
242: T_DOUBLE_COLON => true,
243: T_STRING => true,
244: T_NS_SEPARATOR => true,
245: T_CLASS_C => true,
246: T_DIR => true,
247: T_FILE => true,
248: T_LINE => true,
249: T_FUNC_C => true,
250: T_METHOD_C => true,
251: T_NS_C => true,
252: T_TRAIT_C => true
253: );
254: static $dontResolve = array('true' => true, 'false' => true, 'null' => true);
255:
256:
257: $tokens[] = array(null);
258:
259: $constants = array();
260: $constant = '';
261: $offset = 0;
262: foreach ($tokens as $token) {
263: if (isset($accepted[$token[0]])) {
264: $constant .= $token[1];
265: } elseif ('' !== $constant) {
266: if (!isset($dontResolve[strtolower($constant)])) {
267: $constants[$offset - strlen($constant)] = $constant;
268: }
269: $constant = '';
270: }
271:
272: if (null !== $token[0]) {
273: $offset += strlen($token[1]);
274: }
275: }
276: return $constants;
277: }
278:
279: 280: 281: 282: 283: 284:
285: final private static function evaluate($source) {
286: return eval($source);
287: }
288: }
289: