Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

TokenArrayScanner.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 19.01 KiB


001  <?php
002  /**
003   * Zend Framework (http://framework.zend.com/)
004   *
005   * @link      http://github.com/zendframework/zf2 for the canonical source repository
006   * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
007   * @license   http://framework.zend.com/license/new-bsd New BSD License
008   */
009   
010  namespace Zend\Code\Scanner;
011   
012  use Zend\Code\Annotation\AnnotationManager;
013  use Zend\Code\Exception;
014  use Zend\Code\NameInformation;
015   
016  class TokenArrayScanner implements ScannerInterface
017  {
018      /**
019       * @var bool
020       */
021      protected $isScanned = false;
022   
023      /**
024       * @var array
025       */
026      protected $tokens = array();
027   
028      /**
029       * @var null
030       */
031      protected $docComment = null;
032   
033      /**
034       * @var NameInformation
035       */
036      protected $nameInformation = null;
037   
038      /**
039       * @var array
040       */
041      protected $infos = array();
042   
043      /**
044       * @var AnnotationManager
045       */
046      protected $annotationManager = null;
047   
048      /**
049       * @param null|array $tokens
050       * @param null|AnnotationManager $annotationManager
051       */
052      public function __construct($tokens, AnnotationManager $annotationManager = null)
053      {
054          $this->tokens            = $tokens;
055          $this->annotationManager = $annotationManager;
056      }
057   
058      /**
059       * @return AnnotationManager
060       */
061      public function getAnnotationManager()
062      {
063          return $this->annotationManager;
064      }
065   
066      /**
067       * Get doc comment
068       *
069       * @todo Assignment of $this->docComment should probably be done in scan()
070       *       and then $this->getDocComment() just retrieves it.
071       *
072       * @return string
073       */
074      public function getDocComment()
075      {
076          foreach ($this->tokens as $token) {
077              $type    = $token[0];
078              $value   = $token[1];
079              if (($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) {
080                  continue;
081              } elseif ($type == T_DOC_COMMENT) {
082                  $this->docComment = $value;
083   
084                  return $this->docComment;
085              } else {
086                  // Only whitespace is allowed before file docblocks
087                  return;
088              }
089          }
090      }
091   
092      /**
093       * @return array
094       */
095      public function getNamespaces()
096      {
097          $this->scan();
098   
099          $namespaces = array();
100          foreach ($this->infos as $info) {
101              if ($info['type'] == 'namespace') {
102                  $namespaces[] = $info['namespace'];
103              }
104          }
105   
106          return $namespaces;
107      }
108   
109      /**
110       * @param  null|string $namespace
111       * @return array|null
112       */
113      public function getUses($namespace = null)
114      {
115          $this->scan();
116   
117          return $this->getUsesNoScan($namespace);
118      }
119   
120      /**
121       * @return array
122       */
123      public function getIncludes()
124      {
125          $this->scan();
126          // @todo Implement getIncludes() in TokenArrayScanner
127      }
128   
129      /**
130       * @return array
131       */
132      public function getClassNames()
133      {
134          $this->scan();
135   
136          $return = array();
137          foreach ($this->infos as $info) {
138              if ($info['type'] != 'class') {
139                  continue;
140              }
141   
142              $return[] = $info['name'];
143          }
144   
145          return $return;
146      }
147   
148      /**
149       * @return ClassScanner[]
150       */
151      public function getClasses()
152      {
153          $this->scan();
154   
155          $return = array();
156          foreach ($this->infos as $info) {
157              if ($info['type'] != 'class') {
158                  continue;
159              }
160   
161              $return[] = $this->getClass($info['name']);
162          }
163   
164          return $return;
165      }
166   
167      /**
168       * Return the class object from this scanner
169       *
170       * @param  string|int $name
171       * @throws Exception\InvalidArgumentException
172       * @return ClassScanner
173       */
174      public function getClass($name)
175      {
176          $this->scan();
177   
178          if (is_int($name)) {
179              $info = $this->infos[$name];
180              if ($info['type'] != 'class') {
181                  throw new Exception\InvalidArgumentException('Index of info offset is not about a class');
182              }
183          } elseif (is_string($name)) {
184              $classFound = false;
185              foreach ($this->infos as $info) {
186                  if ($info['type'] === 'class' && $info['name'] === $name) {
187                      $classFound = true;
188                      break;
189                  }
190              }
191   
192              if (!$classFound) {
193                  return false;
194              }
195          }
196   
197          return new ClassScanner(
198              array_slice(
199                  $this->tokens,
200                  $info['tokenStart'],
201                  ($info['tokenEnd'] - $info['tokenStart'] + 1)
202              ), // zero indexed array
203              new NameInformation($info['namespace'], $info['uses'])
204          );
205      }
206   
207      /**
208       * @param  string $className
209       * @return bool|null|NameInformation
210       */
211      public function getClassNameInformation($className)
212      {
213          $this->scan();
214   
215          $classFound = false;
216          foreach ($this->infos as $info) {
217              if ($info['type'] === 'class' && $info['name'] === $className) {
218                  $classFound = true;
219                  break;
220              }
221          }
222   
223          if (!$classFound) {
224              return false;
225          }
226   
227          if (!isset($info)) {
228              return;
229          }
230   
231          return new NameInformation($info['namespace'], $info['uses']);
232      }
233   
234      /**
235       * @return array
236       */
237      public function getFunctionNames()
238      {
239          $this->scan();
240          $functionNames = array();
241          foreach ($this->infos as $info) {
242              if ($info['type'] == 'function') {
243                  $functionNames[] = $info['name'];
244              }
245          }
246   
247          return $functionNames;
248      }
249   
250      /**
251       * @return array
252       */
253      public function getFunctions()
254      {
255          $this->scan();
256   
257          $functions = array();
258          foreach ($this->infos as $info) {
259              if ($info['type'] == 'function') {
260                  // @todo $functions[] = new FunctionScanner($info['name']);
261              }
262          }
263   
264          return $functions;
265      }
266   
267      /**
268       * Export
269       *
270       * @param $tokens
271       */
272      public static function export($tokens)
273      {
274          // @todo
275      }
276   
277      public function __toString()
278      {
279          // @todo
280      }
281   
282      /**
283       * Scan
284       *
285       * @todo: $this->docComment should be assigned for valid docblock during
286       *        the scan instead of $this->getDocComment() (starting with
287       *        T_DOC_COMMENT case)
288       *
289       * @throws Exception\RuntimeException
290       */
291      protected function scan()
292      {
293          if ($this->isScanned) {
294              return;
295          }
296   
297          if (!$this->tokens) {
298              throw new Exception\RuntimeException('No tokens were provided');
299          }
300   
301          /**
302           * Define PHP 5.4 'trait' token constant.
303           */
304          if (!defined('T_TRAIT')) {
305              define('T_TRAIT', 42001);
306          }
307   
308          /**
309           * Variables & Setup
310           */
311   
312          $tokens          = &$this->tokens; // localize
313          $infos           = &$this->infos; // localize
314          $tokenIndex      = null;
315          $token           = null;
316          $tokenType       = null;
317          $tokenContent    = null;
318          $tokenLine       = null;
319          $namespace       = null;
320          $docCommentIndex = false;
321          $infoIndex       = 0;
322   
323          /*
324           * MACRO creation
325           */
326          $MACRO_TOKEN_ADVANCE             = function () use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
327              $tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
328              if (!isset($tokens[$tokenIndex])) {
329                  $token        = false;
330                  $tokenContent = false;
331                  $tokenType    = false;
332                  $tokenLine    = false;
333   
334                  return false;
335              }
336              if (is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"') {
337                  do {
338                      $tokenIndex++;
339                  } while (!(is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"'));
340              }
341              $token = $tokens[$tokenIndex];
342              if (is_array($token)) {
343                  list($tokenType, $tokenContent, $tokenLine) = $token;
344              } else {
345                  $tokenType    = null;
346                  $tokenContent = $token;
347              }
348   
349              return $tokenIndex;
350          };
351          $MACRO_TOKEN_LOGICAL_START_INDEX = function () use (&$tokenIndex, &$docCommentIndex) {
352              return ($docCommentIndex === false) ? $tokenIndex : $docCommentIndex;
353          };
354          $MACRO_DOC_COMMENT_START = function () use (&$tokenIndex, &$docCommentIndex) {
355              $docCommentIndex = $tokenIndex;
356   
357              return $docCommentIndex;
358          };
359          $MACRO_DOC_COMMENT_VALIDATE = function () use (&$tokenType, &$docCommentIndex) {
360              static $validTrailingTokens = null;
361              if ($validTrailingTokens === null) {
362                  $validTrailingTokens = array(T_WHITESPACE, T_FINAL, T_ABSTRACT, T_INTERFACE, T_CLASS, T_FUNCTION);
363              }
364              if ($docCommentIndex !== false && !in_array($tokenType, $validTrailingTokens)) {
365                  $docCommentIndex = false;
366              }
367   
368              return $docCommentIndex;
369          };
370          $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
371              $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
372              $infos[$infoIndex]['lineEnd']  = $tokenLine;
373              $infoIndex++;
374   
375              return $infoIndex;
376          };
377   
378          /**
379           * START FINITE STATE MACHINE FOR SCANNING TOKENS
380           */
381   
382          // Initialize token
383          $MACRO_TOKEN_ADVANCE();
384   
385          SCANNER_TOP:
386   
387          if ($token === false) {
388              goto SCANNER_END;
389          }
390   
391          // Validate current doc comment index
392          $MACRO_DOC_COMMENT_VALIDATE();
393   
394          switch ($tokenType) {
395   
396              case T_DOC_COMMENT:
397   
398                  $MACRO_DOC_COMMENT_START();
399                  goto SCANNER_CONTINUE;
400                  //goto no break needed
401   
402              case T_NAMESPACE:
403   
404                  $infos[$infoIndex] = array(
405                      'type'       => 'namespace',
406                      'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
407                      'tokenEnd'   => null,
408                      'lineStart'  => $token[2],
409                      'lineEnd'    => null,
410                      'namespace'  => null,
411                  );
412   
413                  // start processing with next token
414                  if ($MACRO_TOKEN_ADVANCE() === false) {
415                      goto SCANNER_END;
416                  }
417   
418                  SCANNER_NAMESPACE_TOP:
419   
420                  if ($tokenType === null && $tokenContent === ';' || $tokenContent === '{') {
421                      goto SCANNER_NAMESPACE_END;
422                  }
423   
424                  if ($tokenType === T_WHITESPACE) {
425                      goto SCANNER_NAMESPACE_CONTINUE;
426                  }
427   
428                  if ($tokenType === T_NS_SEPARATOR || $tokenType === T_STRING) {
429                      $infos[$infoIndex]['namespace'] .= $tokenContent;
430                  }
431   
432                  SCANNER_NAMESPACE_CONTINUE:
433   
434                  if ($MACRO_TOKEN_ADVANCE() === false) {
435                      goto SCANNER_END;
436                  }
437                  goto SCANNER_NAMESPACE_TOP;
438   
439                  SCANNER_NAMESPACE_END:
440   
441                  $namespace = $infos[$infoIndex]['namespace'];
442   
443                  $MACRO_INFO_ADVANCE();
444                  goto SCANNER_CONTINUE;
445                  //goto no break needed
446   
447              case T_USE:
448   
449                  $infos[$infoIndex] = array(
450                      'type'       => 'use',
451                      'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
452                      'tokenEnd'   => null,
453                      'lineStart'  => $tokens[$tokenIndex][2],
454                      'lineEnd'    => null,
455                      'namespace'  => $namespace,
456                      'statements' => array(0 => array('use' => null,
457                                                       'as'  => null)),
458                  );
459   
460                  $useStatementIndex = 0;
461                  $useAsContext      = false;
462   
463                  // start processing with next token
464                  if ($MACRO_TOKEN_ADVANCE() === false) {
465                      goto SCANNER_END;
466                  }
467   
468                  SCANNER_USE_TOP:
469   
470                  if ($tokenType === null) {
471                      if ($tokenContent === ';') {
472                          goto SCANNER_USE_END;
473                      } elseif ($tokenContent === ',') {
474                          $useAsContext = false;
475                          $useStatementIndex++;
476                          $infos[$infoIndex]['statements'][$useStatementIndex] = array('use' => null,
477                                                                                       'as'  => null);
478                      }
479                  }
480   
481                  // ANALYZE
482                  if ($tokenType !== null) {
483                      if ($tokenType == T_AS) {
484                          $useAsContext = true;
485                          goto SCANNER_USE_CONTINUE;
486                      }
487   
488                      if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) {
489                          if ($useAsContext == false) {
490                              $infos[$infoIndex]['statements'][$useStatementIndex]['use'] .= $tokenContent;
491                          } else {
492                              $infos[$infoIndex]['statements'][$useStatementIndex]['as'] = $tokenContent;
493                          }
494                      }
495                  }
496   
497                  SCANNER_USE_CONTINUE:
498   
499                  if ($MACRO_TOKEN_ADVANCE() === false) {
500                      goto SCANNER_END;
501                  }
502                  goto SCANNER_USE_TOP;
503   
504                  SCANNER_USE_END:
505   
506                  $MACRO_INFO_ADVANCE();
507                  goto SCANNER_CONTINUE;
508                  //goto no break needed
509   
510              case T_INCLUDE:
511              case T_INCLUDE_ONCE:
512              case T_REQUIRE:
513              case T_REQUIRE_ONCE:
514   
515                  // Static for performance
516                  static $includeTypes = array(
517                      T_INCLUDE      => 'include',
518                      T_INCLUDE_ONCE => 'include_once',
519                      T_REQUIRE      => 'require',
520                      T_REQUIRE_ONCE => 'require_once'
521                  );
522   
523                  $infos[$infoIndex] = array(
524                      'type'        => 'include',
525                      'tokenStart'  => $MACRO_TOKEN_LOGICAL_START_INDEX(),
526                      'tokenEnd'    => null,
527                      'lineStart'   => $tokens[$tokenIndex][2],
528                      'lineEnd'     => null,
529                      'includeType' => $includeTypes[$tokens[$tokenIndex][0]],
530                      'path'        => '',
531                  );
532   
533                  // start processing with next token
534                  if ($MACRO_TOKEN_ADVANCE() === false) {
535                      goto SCANNER_END;
536                  }
537   
538                  SCANNER_INCLUDE_TOP:
539   
540                  if ($tokenType === null && $tokenContent === ';') {
541                      goto SCANNER_INCLUDE_END;
542                  }
543   
544                  $infos[$infoIndex]['path'] .= $tokenContent;
545   
546                  SCANNER_INCLUDE_CONTINUE:
547   
548                  if ($MACRO_TOKEN_ADVANCE() === false) {
549                      goto SCANNER_END;
550                  }
551                  goto SCANNER_INCLUDE_TOP;
552   
553                  SCANNER_INCLUDE_END:
554   
555                  $MACRO_INFO_ADVANCE();
556                  goto SCANNER_CONTINUE;
557                  //goto no break needed
558   
559              case T_FUNCTION:
560              case T_FINAL:
561              case T_ABSTRACT:
562              case T_CLASS:
563              case T_INTERFACE:
564              case T_TRAIT:
565   
566                  $infos[$infoIndex] = array(
567                      'type'        => ($tokenType === T_FUNCTION) ? 'function' : 'class',
568                      'tokenStart'  => $MACRO_TOKEN_LOGICAL_START_INDEX(),
569                      'tokenEnd'    => null,
570                      'lineStart'   => $tokens[$tokenIndex][2],
571                      'lineEnd'     => null,
572                      'namespace'   => $namespace,
573                      'uses'        => $this->getUsesNoScan($namespace),
574                      'name'        => null,
575                      'shortName'   => null,
576                  );
577   
578                  $classBraceCount = 0;
579   
580                  // start processing with current token
581   
582                  SCANNER_CLASS_TOP:
583   
584                  // process the name
585                  if ($infos[$infoIndex]['shortName'] == ''
586                      && (($tokenType === T_CLASS || $tokenType === T_INTERFACE || $tokenType === T_TRAIT) && $infos[$infoIndex]['type'] === 'class'
587                          || ($tokenType === T_FUNCTION && $infos[$infoIndex]['type'] === 'function'))
588                  ) {
589                      $infos[$infoIndex]['shortName'] = $tokens[$tokenIndex + 2][1];
590                      $infos[$infoIndex]['name']      = (($namespace !== null) ? $namespace . '\\' : '') . $infos[$infoIndex]['shortName'];
591                  }
592   
593                  if ($tokenType === null) {
594                      if ($tokenContent == '{') {
595                          $classBraceCount++;
596                      }
597                      if ($tokenContent == '}') {
598                          $classBraceCount--;
599                          if ($classBraceCount === 0) {
600                              goto SCANNER_CLASS_END;
601                          }
602                      }
603                  }
604   
605                  SCANNER_CLASS_CONTINUE:
606   
607                  if ($MACRO_TOKEN_ADVANCE() === false) {
608                      goto SCANNER_END;
609                  }
610                  goto SCANNER_CLASS_TOP;
611   
612                  SCANNER_CLASS_END:
613   
614                  $MACRO_INFO_ADVANCE();
615                  goto SCANNER_CONTINUE;
616   
617          }
618   
619          SCANNER_CONTINUE:
620   
621          if ($MACRO_TOKEN_ADVANCE() === false) {
622              goto SCANNER_END;
623          }
624          goto SCANNER_TOP;
625   
626          SCANNER_END:
627   
628          /**
629           * END FINITE STATE MACHINE FOR SCANNING TOKENS
630           */
631   
632          $this->isScanned = true;
633      }
634   
635      /**
636       * Check for namespace
637       *
638       * @param string $namespace
639       * @return bool
640       */
641      public function hasNamespace($namespace)
642      {
643          $this->scan();
644   
645          foreach ($this->infos as $info) {
646              if ($info['type'] == 'namespace' && $info['namespace'] == $namespace) {
647                  return true;
648              }
649          }
650          return false;
651      }
652   
653      /**
654       * @param  string $namespace
655       * @return null|array
656       * @throws Exception\InvalidArgumentException
657       */
658      protected function getUsesNoScan($namespace)
659      {
660          $namespaces = array();
661          foreach ($this->infos as $info) {
662              if ($info['type'] == 'namespace') {
663                  $namespaces[] = $info['namespace'];
664              }
665          }
666   
667          if ($namespace === null) {
668              $namespace = array_shift($namespaces);
669          } elseif (!is_string($namespace)) {
670              throw new Exception\InvalidArgumentException('Invalid namespace provided');
671          } elseif (!in_array($namespace, $namespaces)) {
672              return;
673          }
674   
675          $uses = array();
676          foreach ($this->infos as $info) {
677              if ($info['type'] !== 'use') {
678                  continue;
679              }
680              foreach ($info['statements'] as $statement) {
681                  if ($info['namespace'] == $namespace) {
682                      $uses[] = $statement;
683                  }
684              }
685          }
686   
687          return $uses;
688      }
689  }
690