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