Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

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

MethodReflection.php

Zuletzt modifiziert: 01.05.2026, 11:27 - Dateigröße: 14.84 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-2016 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\Reflection;
 011   
 012  use ReflectionMethod as PhpReflectionMethod;
 013  use Zend\Code\Annotation\AnnotationManager;
 014  use Zend\Code\Scanner\AnnotationScanner;
 015  use Zend\Code\Scanner\CachingFileScanner;
 016   
 017  use function array_shift;
 018  use function array_slice;
 019  use function class_exists;
 020  use function count;
 021  use function file;
 022  use function file_exists;
 023  use function implode;
 024  use function is_array;
 025  use function rtrim;
 026  use function strlen;
 027  use function substr;
 028  use function token_get_all;
 029  use function token_name;
 030  use function var_export;
 031   
 032  class MethodReflection extends PhpReflectionMethod implements ReflectionInterface
 033  {
 034      /**
 035       * Constant use in @MethodReflection to display prototype as an array
 036       */
 037      const PROTOTYPE_AS_ARRAY = 'prototype_as_array';
 038   
 039      /**
 040       * Constant use in @MethodReflection to display prototype as a string
 041       */
 042      const PROTOTYPE_AS_STRING = 'prototype_as_string';
 043   
 044      /**
 045       * @var AnnotationScanner
 046       */
 047      protected $annotations;
 048   
 049      /**
 050       * Retrieve method DocBlock reflection
 051       *
 052       * @return DocBlockReflection|false
 053       */
 054      public function getDocBlock()
 055      {
 056          if ('' == $this->getDocComment()) {
 057              return false;
 058          }
 059   
 060          $instance = new DocBlockReflection($this);
 061   
 062          return $instance;
 063      }
 064   
 065      /**
 066       * @param  AnnotationManager $annotationManager
 067       * @return AnnotationScanner|false
 068       */
 069      public function getAnnotations(AnnotationManager $annotationManager)
 070      {
 071          if (($docComment = $this->getDocComment()) == '') {
 072              return false;
 073          }
 074   
 075          if ($this->annotations) {
 076              return $this->annotations;
 077          }
 078   
 079          $cachingFileScanner = $this->createFileScanner($this->getFileName());
 080          $nameInformation    = $cachingFileScanner->getClassNameInformation($this->getDeclaringClass()->getName());
 081   
 082          if (! $nameInformation) {
 083              return false;
 084          }
 085   
 086          $this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
 087   
 088          return $this->annotations;
 089      }
 090   
 091      /**
 092       * Get start line (position) of method
 093       *
 094       * @param  bool $includeDocComment
 095       * @return int
 096       */
 097      public function getStartLine($includeDocComment = false)
 098      {
 099          if ($includeDocComment) {
 100              if ($this->getDocComment() != '') {
 101                  return $this->getDocBlock()->getStartLine();
 102              }
 103          }
 104   
 105          return parent::getStartLine();
 106      }
 107   
 108      /**
 109       * Get reflection of declaring class
 110       *
 111       * @return ClassReflection
 112       */
 113      public function getDeclaringClass()
 114      {
 115          $phpReflection  = parent::getDeclaringClass();
 116          $zendReflection = new ClassReflection($phpReflection->getName());
 117          unset($phpReflection);
 118   
 119          return $zendReflection;
 120      }
 121   
 122      /**
 123       * Get method prototype
 124       *
 125       * @param string $format
 126       * @return array|string
 127       */
 128      public function getPrototype($format = MethodReflection::PROTOTYPE_AS_ARRAY)
 129      {
 130          $returnType = 'mixed';
 131          $docBlock = $this->getDocBlock();
 132          if ($docBlock) {
 133              $return = $docBlock->getTag('return');
 134              $returnTypes = $return->getTypes();
 135              $returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];
 136          }
 137   
 138          $declaringClass = $this->getDeclaringClass();
 139          $prototype = [
 140              'namespace'  => $declaringClass->getNamespaceName(),
 141              'class'      => substr($declaringClass->getName(), strlen($declaringClass->getNamespaceName()) + 1),
 142              'name'       => $this->getName(),
 143              'visibility' => $this->isPublic() ? 'public' : ($this->isPrivate() ? 'private' : 'protected'),
 144              'return'     => $returnType,
 145              'arguments'  => [],
 146          ];
 147   
 148          $parameters = $this->getParameters();
 149          foreach ($parameters as $parameter) {
 150              $prototype['arguments'][$parameter->getName()] = [
 151                  'type'     => $parameter->detectType(),
 152                  'required' => ! $parameter->isOptional(),
 153                  'by_ref'   => $parameter->isPassedByReference(),
 154                  'default'  => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
 155              ];
 156          }
 157   
 158          if ($format == MethodReflection::PROTOTYPE_AS_STRING) {
 159              $line = $prototype['visibility'] . ' ' . $prototype['return'] . ' ' . $prototype['name'] . '(';
 160              $args = [];
 161              foreach ($prototype['arguments'] as $name => $argument) {
 162                  $argsLine = ($argument['type'] ?
 163                      $argument['type'] . ' '
 164                      : '') . ($argument['by_ref'] ? '&' : '') . '$' . $name;
 165                  if (! $argument['required']) {
 166                      $argsLine .= ' = ' . var_export($argument['default'], true);
 167                  }
 168                  $args[] = $argsLine;
 169              }
 170              $line .= implode(', ', $args);
 171              $line .= ')';
 172   
 173              return $line;
 174          }
 175   
 176          return $prototype;
 177      }
 178   
 179      /**
 180       * Get all method parameter reflection objects
 181       *
 182       * @return ParameterReflection[]
 183       */
 184      public function getParameters()
 185      {
 186          $phpReflections  = parent::getParameters();
 187          $zendReflections = [];
 188          while ($phpReflections && ($phpReflection = array_shift($phpReflections))) {
 189              $instance = new ParameterReflection(
 190                  [$this->getDeclaringClass()->getName(), $this->getName()],
 191                  $phpReflection->getName()
 192              );
 193              $zendReflections[] = $instance;
 194              unset($phpReflection);
 195          }
 196          unset($phpReflections);
 197   
 198          return $zendReflections;
 199      }
 200   
 201      /**
 202       * Get method contents
 203       *
 204       * @param  bool $includeDocBlock
 205       * @return string
 206       */
 207      public function getContents($includeDocBlock = true)
 208      {
 209          $docComment = $this->getDocComment();
 210          $content  = $includeDocBlock && ! empty($docComment) ? $docComment . "\n" : '';
 211          $content .= $this->extractMethodContents();
 212   
 213          return $content;
 214      }
 215   
 216      /**
 217       * Get method body
 218       *
 219       * @return string
 220       */
 221      public function getBody()
 222      {
 223          return $this->extractMethodContents(true);
 224      }
 225   
 226      /**
 227       * Tokenize method string and return concatenated body
 228       *
 229       * @param bool $bodyOnly
 230       * @return string
 231       */
 232      protected function extractMethodContents($bodyOnly = false)
 233      {
 234          $fileName = $this->getFileName();
 235   
 236          if ((class_exists($this->class) && false === $fileName) || ! file_exists($fileName)) {
 237              return '';
 238          }
 239   
 240          $lines = array_slice(
 241              file($fileName, FILE_IGNORE_NEW_LINES),
 242              $this->getStartLine() - 1,
 243              $this->getEndLine() - ($this->getStartLine() - 1),
 244              true
 245          );
 246   
 247          $functionLine = implode("\n", $lines);
 248          $tokens = token_get_all('<?php ' . $functionLine);
 249   
 250          //remove first entry which is php open tag
 251          array_shift($tokens);
 252   
 253          if (! count($tokens)) {
 254              return '';
 255          }
 256   
 257          $capture = false;
 258          $firstBrace = false;
 259          $body = '';
 260   
 261          foreach ($tokens as $key => $token) {
 262              $tokenType  = is_array($token) ? token_name($token[0]) : $token;
 263              $tokenValue = is_array($token) ? $token[1] : $token;
 264   
 265              switch ($tokenType) {
 266                  case 'T_FINAL':
 267                  case 'T_ABSTRACT':
 268                  case 'T_PUBLIC':
 269                  case 'T_PROTECTED':
 270                  case 'T_PRIVATE':
 271                  case 'T_STATIC':
 272                  case 'T_FUNCTION':
 273                      // check to see if we have a valid function
 274                      // then check if we are inside function and have a closure
 275                      if ($this->isValidFunction($tokens, $key, $this->getName())) {
 276                          if ($bodyOnly === false) {
 277                              //if first instance of tokenType grab prefixed whitespace
 278                              //and append to body
 279                              if ($capture === false) {
 280                                  $body .= $this->extractPrefixedWhitespace($tokens, $key);
 281                              }
 282                              $body .= $tokenValue;
 283                          }
 284   
 285                          $capture = true;
 286                      } else {
 287                          //closure test
 288                          if ($firstBrace && $tokenType == 'T_FUNCTION') {
 289                              $body .= $tokenValue;
 290                              break;
 291                          }
 292                          $capture = false;
 293                          break;
 294                      }
 295                      break;
 296   
 297                  case '{':
 298                      if ($capture === false) {
 299                          break;
 300                      }
 301   
 302                      if ($firstBrace === false) {
 303                          $firstBrace = true;
 304                          if ($bodyOnly === true) {
 305                              break;
 306                          }
 307                      }
 308   
 309                      $body .= $tokenValue;
 310                      break;
 311   
 312                  case '}':
 313                      if ($capture === false) {
 314                          break;
 315                      }
 316   
 317                      //check to see if this is the last brace
 318                      if ($this->isEndingBrace($tokens, $key)) {
 319                          //capture the end brace if not bodyOnly
 320                          if ($bodyOnly === false) {
 321                              $body .= $tokenValue;
 322                          }
 323   
 324                          break 2;
 325                      }
 326   
 327                      $body .= $tokenValue;
 328                      break;
 329   
 330                  default:
 331                      if ($capture === false) {
 332                          break;
 333                      }
 334   
 335                      // if returning body only wait for first brace before capturing
 336                      if ($bodyOnly === true && $firstBrace !== true) {
 337                          break;
 338                      }
 339   
 340                      $body .= $tokenValue;
 341                      break;
 342              }
 343          }
 344   
 345          //remove ending whitespace and return
 346          return rtrim($body);
 347      }
 348   
 349      /**
 350       * Take current position and find any whitespace
 351       *
 352       * @param array $haystack
 353       * @param int $position
 354       * @return string
 355       */
 356      protected function extractPrefixedWhitespace($haystack, $position)
 357      {
 358          $content = '';
 359          $count = count($haystack);
 360          if ($position + 1 == $count) {
 361              return $content;
 362          }
 363   
 364          for ($i = $position - 1; $i >= 0; $i--) {
 365              $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i];
 366              $tokenValue = is_array($haystack[$i]) ? $haystack[$i][1] : $haystack[$i];
 367   
 368              //search only for whitespace
 369              if ($tokenType == 'T_WHITESPACE') {
 370                  $content .= $tokenValue;
 371              } else {
 372                  break;
 373              }
 374          }
 375   
 376          return $content;
 377      }
 378   
 379      /**
 380       * Test for ending brace
 381       *
 382       * @param array $haystack
 383       * @param int $position
 384       * @return bool
 385       */
 386      protected function isEndingBrace($haystack, $position)
 387      {
 388          $count = count($haystack);
 389   
 390          //advance one position
 391          $position = $position + 1;
 392   
 393          if ($position == $count) {
 394              return true;
 395          }
 396   
 397          for ($i = $position; $i < $count; $i++) {
 398              $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i];
 399              switch ($tokenType) {
 400                  case 'T_FINAL':
 401                  case 'T_ABSTRACT':
 402                  case 'T_PUBLIC':
 403                  case 'T_PROTECTED':
 404                  case 'T_PRIVATE':
 405                  case 'T_STATIC':
 406                      return true;
 407   
 408                  case 'T_FUNCTION':
 409                      // If a function is encountered and that function is not a closure
 410                      // then return true.  otherwise the function is a closure, return false
 411                      if ($this->isValidFunction($haystack, $i)) {
 412                          return true;
 413                      }
 414                      return false;
 415   
 416                  case '}':
 417                  case ';':
 418                  case 'T_BREAK':
 419                  case 'T_CATCH':
 420                  case 'T_DO':
 421                  case 'T_ECHO':
 422                  case 'T_ELSE':
 423                  case 'T_ELSEIF':
 424                  case 'T_EVAL':
 425                  case 'T_EXIT':
 426                  case 'T_FINALLY':
 427                  case 'T_FOR':
 428                  case 'T_FOREACH':
 429                  case 'T_GOTO':
 430                  case 'T_IF':
 431                  case 'T_INCLUDE':
 432                  case 'T_INCLUDE_ONCE':
 433                  case 'T_PRINT':
 434                  case 'T_STRING':
 435                  case 'T_STRING_VARNAME':
 436                  case 'T_THROW':
 437                  case 'T_USE':
 438                  case 'T_VARIABLE':
 439                  case 'T_WHILE':
 440                  case 'T_YIELD':
 441                      return false;
 442              }
 443          }
 444      }
 445   
 446      /**
 447       * Test to see if current position is valid function or
 448       * closure.  Returns true if it's a function and NOT a closure
 449       *
 450       * @param array $haystack
 451       * @param int $position
 452       * @param string $functionName
 453       * @return bool
 454       */
 455      protected function isValidFunction($haystack, $position, $functionName = null)
 456      {
 457          $isValid = false;
 458          $count = count($haystack);
 459          for ($i = $position + 1; $i < $count; $i++) {
 460              $tokenType = is_array($haystack[$i]) ? token_name($haystack[$i][0]) : $haystack[$i];
 461              $tokenValue = is_array($haystack[$i]) ? $haystack[$i][1] : $haystack[$i];
 462   
 463              //check for occurrence of ( or
 464              if ($tokenType == 'T_STRING') {
 465                  //check to see if function name is passed, if so validate against that
 466                  if ($functionName !== null && $tokenValue != $functionName) {
 467                      $isValid = false;
 468                      break;
 469                  }
 470   
 471                  $isValid = true;
 472                  break;
 473              } elseif ($tokenValue == '(') {
 474                  break;
 475              }
 476          }
 477   
 478          return $isValid;
 479      }
 480   
 481      /**
 482       * @return string
 483       */
 484      public function toString()
 485      {
 486          return parent::__toString();
 487      }
 488   
 489      /**
 490       * @return string
 491       */
 492      public function __toString()
 493      {
 494          return parent::__toString();
 495      }
 496   
 497      /**
 498       * Creates a new FileScanner instance.
 499       *
 500       * By having this as a separate method it allows the method to be overridden
 501       * if a different FileScanner is needed.
 502       *
 503       * @param  string $filename
 504       *
 505       * @return CachingFileScanner
 506       */
 507      protected function createFileScanner($filename)
 508      {
 509          return new CachingFileScanner($filename);
 510      }
 511  }
 512