1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: namespace TokenReflection\Broker\Backend;
17:
18: use TokenReflection;
19: use TokenReflection\Stream\FileStream, TokenReflection\Exception, TokenReflection\Broker, TokenReflection\Php, TokenReflection\Dummy;
20:
21: 22: 23: 24: 25:
26: class Memory implements Broker\Backend
27: {
28: 29: 30: 31: 32:
33: private $declaredClasses = array();
34:
35: 36: 37: 38: 39:
40: private $namespaces = array();
41:
42: 43: 44: 45: 46:
47: private $allConstants;
48:
49: 50: 51: 52: 53:
54: private $allClasses;
55:
56: 57: 58: 59: 60:
61: private $allFunctions;
62:
63: 64: 65: 66: 67:
68: private $tokenStreams = array();
69:
70: 71: 72: 73: 74:
75: private $files = array();
76:
77: 78: 79: 80: 81:
82: private $broker;
83:
84: 85: 86: 87: 88:
89: private $storingTokenStreams;
90:
91: 92: 93: 94: 95: 96:
97: public function hasFile($fileName)
98: {
99: return isset($this->files[$fileName]);
100: }
101:
102: 103: 104: 105: 106: 107: 108:
109: public function getFile($fileName)
110: {
111: if (!isset($this->files[$fileName])) {
112: throw new Exception\BrokerException($this->getBroker(), sprintf('File "%s" has not been processed.', $fileName), Exception\BrokerException::DOES_NOT_EXIST);
113: }
114:
115: return $this->files[$fileName];
116: }
117:
118: 119: 120: 121: 122:
123: public function getFiles()
124: {
125: return $this->files;
126: }
127:
128: 129: 130: 131: 132: 133:
134: public function hasNamespace($namespaceName)
135: {
136: return isset($this->namespaces[ltrim($namespaceName, '\\')]);
137: }
138:
139: 140: 141: 142: 143: 144: 145:
146: public function getNamespace($namespaceName)
147: {
148: if (!isset($this->namespaces[TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME])) {
149: $this->namespaces[TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME] = new TokenReflection\ReflectionNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME, $this->broker);
150: }
151:
152: $namespaceName = ltrim($namespaceName, '\\');
153: if (!isset($this->namespaces[$namespaceName])) {
154: throw new Exception\BrokerException($this->getBroker(), sprintf('Namespace %s does not exist.', $namespaceName), Exception\BrokerException::DOES_NOT_EXIST);
155: }
156:
157: return $this->namespaces[$namespaceName];
158: }
159:
160: 161: 162: 163: 164:
165: public function getNamespaces()
166: {
167: return $this->namespaces;
168: }
169:
170: 171: 172: 173: 174: 175:
176: public function hasClass($className)
177: {
178: $className = ltrim($className, '\\');
179: if ($pos = strrpos($className, '\\')) {
180: $namespace = substr($className, 0, $pos);
181:
182: if (!isset($this->namespaces[$namespace])) {
183: return false;
184: }
185:
186: $namespace = $this->getNamespace($namespace);
187: $className = substr($className, $pos + 1);
188: } else {
189: $namespace = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME);
190: }
191:
192: return $namespace->hasClass($className);
193: }
194:
195: 196: 197: 198: 199: 200:
201: public function getClass($className)
202: {
203: if (empty($this->declaredClasses)) {
204: $this->declaredClasses = array_flip(array_merge(get_declared_classes(), get_declared_interfaces()));
205: }
206:
207: $className = ltrim($className, '\\');
208: try {
209: $ns = $this->getNamespace(
210: ($boundary = strrpos($className, '\\'))
211:
212: ? substr($className, 0, $boundary)
213:
214: : TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME
215: );
216:
217: return $ns->getClass($className);
218: } catch (Exception\BaseException $e) {
219: if (isset($this->declaredClasses[$className])) {
220: $reflection = new Php\ReflectionClass($className, $this->broker);
221: if ($reflection->isInternal()) {
222: return $reflection;
223: }
224: }
225:
226: return new Dummy\ReflectionClass($className, $this->broker);
227: }
228: }
229:
230: 231: 232: 233: 234: 235:
236: public function getClasses($type = self::TOKENIZED_CLASSES)
237: {
238: if (null === $this->allClasses) {
239: $this->allClasses = $this->parseClassLists();
240: }
241:
242: $result = array();
243: foreach ($this->allClasses as $classType => $classes) {
244: if ($type & $classType) {
245: $result = array_merge($result, $classes);
246: }
247: }
248: return $result;
249: }
250:
251: 252: 253: 254: 255: 256:
257: public function hasConstant($constantName)
258: {
259: $constantName = ltrim($constantName, '\\');
260:
261: if ($pos = strpos($constantName, '::')) {
262: $className = substr($constantName, 0, $pos);
263: $constantName = substr($constantName, $pos + 2);
264:
265: if (!$this->hasClass($className)) {
266: return false;
267: }
268:
269: $parent = $this->getClass($className);
270: } else {
271: if ($pos = strrpos($constantName, '\\')) {
272: $namespace = substr($constantName, 0, $pos);
273: if (!$this->hasNamespace($namespace)) {
274: return false;
275: }
276:
277: $parent = $this->getNamespace($namespace);
278: $constantName = substr($constantName, $pos + 1);
279: } else {
280: $parent = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME);
281: }
282: }
283:
284: return $parent->hasConstant($constantName);
285: }
286:
287: 288: 289: 290: 291: 292: 293:
294: public function getConstant($constantName)
295: {
296: static $declared = array();
297: if (empty($declared)) {
298: $declared = get_defined_constants();
299: }
300:
301: if ($boundary = strpos($constantName, '::')) {
302:
303: $className = substr($constantName, 0, $boundary);
304: $constantName = substr($constantName, $boundary + 2);
305:
306: return $this->getClass($className)->getConstantReflection($constantName);
307: }
308:
309: try {
310: $constantName = ltrim($constantName, '\\');
311: if ($boundary = strrpos($constantName, '\\')) {
312: $ns = $this->getNamespace(substr($constantName, 0, $boundary));
313: $constantName = substr($constantName, $boundary + 1);
314: } else {
315: $ns = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME);
316: }
317:
318: return $ns->getConstant($constantName);
319: } catch (Exception\BaseException $e) {
320: if (isset($declared[$constantName])) {
321: $reflection = new Php\ReflectionConstant($constantName, $declared[$constantName], $this->broker);
322: if ($reflection->isInternal()) {
323: return $reflection;
324: }
325: }
326:
327: throw new Exception\BrokerException($this->getBroker(), sprintf('Constant %s does not exist.', $constantName), Exception\BrokerException::DOES_NOT_EXIST);
328: }
329: }
330:
331: 332: 333: 334: 335:
336: public function getConstants()
337: {
338: if (null === $this->allConstants) {
339: $this->allConstants = array();
340: foreach ($this->namespaces as $namespace) {
341: foreach ($namespace->getConstants() as $constant) {
342: $this->allConstants[$constant->getName()] = $constant;
343: }
344: }
345: }
346:
347: return $this->allConstants;
348: }
349:
350: 351: 352: 353: 354: 355:
356: public function hasFunction($functionName)
357: {
358: $functionName = ltrim($functionName, '\\');
359: if ($pos = strrpos($functionName, '\\')) {
360: $namespace = substr($functionName, 0, $pos);
361: if (!isset($this->namespaces[$namespace])) {
362: return false;
363: }
364:
365: $namespace = $this->getNamespace($namespace);
366: $functionName = substr($functionName, $pos + 1);
367: } else {
368: $namespace = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME);
369: }
370:
371: return $namespace->hasFunction($functionName);
372: }
373:
374: 375: 376: 377: 378: 379: 380:
381: public function getFunction($functionName)
382: {
383: static $declared = array();
384: if (empty($declared)) {
385: $functions = get_defined_functions();
386: $declared = array_flip($functions['internal']);
387: }
388:
389: $functionName = ltrim($functionName, '\\');
390: try {
391: $ns = $this->getNamespace(
392: ($boundary = strrpos($functionName, '\\'))
393:
394: ? substr($functionName, 0, $boundary)
395:
396: : TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME
397: );
398:
399: return $ns->getFunction($functionName);
400: } catch (Exception\BaseException $e) {
401: if (isset($declared[$functionName])) {
402: return new Php\ReflectionFunction($functionName, $this->broker);
403: }
404:
405: throw new Exception\BrokerException($this->getBroker(), sprintf('Function %s does not exist.', $functionName), Exception\BrokerException::DOES_NOT_EXIST);
406: }
407: }
408:
409: 410: 411: 412: 413:
414: public function getFunctions()
415: {
416: if (null === $this->allFunctions) {
417: $this->allFunctions = array();
418: foreach ($this->namespaces as $namespace) {
419: foreach ($namespace->getFunctions() as $function) {
420: $this->allFunctions[$function->getName()] = $function;
421: }
422: }
423: }
424:
425: return $this->allFunctions;
426: }
427:
428: 429: 430: 431: 432: 433:
434: public function isFileProcessed($fileName)
435: {
436: return isset($this->tokenStreams[Broker::getRealPath($fileName)]);
437: }
438:
439: 440: 441: 442: 443: 444: 445:
446: public function getFileTokens($fileName)
447: {
448: $realName = Broker::getRealPath($fileName);
449: if (!isset($this->tokenStreams[$realName])) {
450: throw new Exception\BrokerException($this->getBroker(), sprintf('File "%s" was not processed yet.', $fileName), Exception\BrokerException::DOES_NOT_EXIST);
451: }
452:
453: return true === $this->tokenStreams[$realName] ? new FileStream($realName) : $this->tokenStreams[$realName];
454: }
455:
456: 457: 458: 459: 460: 461: 462:
463: public function addFile(TokenReflection\Stream\StreamBase $tokenStream, TokenReflection\ReflectionFile $file)
464: {
465: $this->tokenStreams[$file->getName()] = $this->storingTokenStreams ? $tokenStream : true;
466: $this->files[$file->getName()] = $file;
467:
468: $errors = array();
469:
470: foreach ($file->getNamespaces() as $fileNamespace) {
471: try {
472: $namespaceName = $fileNamespace->getName();
473: if (!isset($this->namespaces[$namespaceName])) {
474: $this->namespaces[$namespaceName] = new TokenReflection\ReflectionNamespace($namespaceName, $file->getBroker());
475: }
476:
477: $this->namespaces[$namespaceName]->addFileNamespace($fileNamespace);
478: } catch (Exception\FileProcessingException $e) {
479: $errors = array_merge($errors, $e->getReasons());
480: } catch (\Exception $e) {
481: echo $e->getTraceAsString();
482: die($e->getMessage());
483: }
484: }
485:
486:
487: $this->allClasses = null;
488: $this->allFunctions = null;
489: $this->allConstants = null;
490:
491: if (!empty($errors)) {
492: throw new Exception\FileProcessingException($errors, $file);
493: }
494:
495: return $this;
496: }
497:
498: 499: 500: 501: 502: 503:
504: public function setBroker(Broker $broker)
505: {
506: $this->broker = $broker;
507: return $this;
508: }
509:
510: 511: 512: 513: 514:
515: public function getBroker()
516: {
517: return $this->broker;
518: }
519:
520: 521: 522: 523: 524: 525:
526: public function setStoringTokenStreams($store)
527: {
528: $this->storingTokenStreams = (bool) $store;
529: return $this;
530: }
531:
532: 533: 534: 535: 536:
537: public function getStoringTokenStreams()
538: {
539: return $this->storingTokenStreams;
540: }
541:
542: 543: 544: 545: 546:
547: protected function parseClassLists()
548: {
549:
550: $allClasses = array(
551: self::TOKENIZED_CLASSES => array(),
552: self::INTERNAL_CLASSES => array(),
553: self::NONEXISTENT_CLASSES => array()
554: );
555:
556: foreach ($this->namespaces as $namespace) {
557: foreach ($namespace->getClasses() as $class) {
558: $allClasses[self::TOKENIZED_CLASSES][$class->getName()] = $class;
559: }
560: }
561:
562: foreach ($allClasses[self::TOKENIZED_CLASSES] as $className => $class) {
563: foreach (array_merge($class->getParentClasses(), $class->getInterfaces()) as $parent) {
564: if ($parent->isInternal()) {
565: $allClasses[self::INTERNAL_CLASSES][$parent->getName()] = $parent;
566: } elseif (!$parent->isTokenized()) {
567: $allClasses[self::NONEXISTENT_CLASSES][$parent->getName()] = $parent;
568: }
569: }
570: }
571:
572: return $allClasses;
573: }
574: }
575: