[ Index ]

PHP Cross Reference of phpBB-3.3.2-deutsch

title

Body

[close]

/vendor/zendframework/zend-code/src/Reflection/ -> MethodReflection.php (source)

   1  <?php
   2  /**
   3   * Zend Framework (http://framework.zend.com/)
   4   *
   5   * @link      http://github.com/zendframework/zf2 for the canonical source repository
   6   * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
   7   * @license   http://framework.zend.com/license/new-bsd New BSD License
   8   */
   9  
  10  namespace Zend\Code\Reflection;
  11  
  12  use ReflectionMethod as PhpReflectionMethod;
  13  use Zend\Code\Annotation\AnnotationManager;
  14  use Zend\Code\Scanner\AnnotationScanner;
  15  use Zend\Code\Scanner\CachingFileScanner;
  16  
  17  use function array_shift;
  18  use function array_slice;
  19  use function class_exists;
  20  use function count;
  21  use function file;
  22  use function file_exists;
  23  use function implode;
  24  use function is_array;
  25  use function rtrim;
  26  use function strlen;
  27  use function substr;
  28  use function token_get_all;
  29  use function token_name;
  30  use function var_export;
  31  
  32  class MethodReflection extends PhpReflectionMethod implements ReflectionInterface
  33  {
  34      /**
  35       * Constant use in @MethodReflection to display prototype as an array
  36       */
  37      const PROTOTYPE_AS_ARRAY = 'prototype_as_array';
  38  
  39      /**
  40       * Constant use in @MethodReflection to display prototype as a string
  41       */
  42      const PROTOTYPE_AS_STRING = 'prototype_as_string';
  43  
  44      /**
  45       * @var AnnotationScanner
  46       */
  47      protected $annotations;
  48  
  49      /**
  50       * Retrieve method DocBlock reflection
  51       *
  52       * @return DocBlockReflection|false
  53       */
  54      public function getDocBlock()
  55      {
  56          if ('' == $this->getDocComment()) {
  57              return false;
  58          }
  59  
  60          $instance = new DocBlockReflection($this);
  61  
  62          return $instance;
  63      }
  64  
  65      /**
  66       * @param  AnnotationManager $annotationManager
  67       * @return AnnotationScanner|false
  68       */
  69      public function getAnnotations(AnnotationManager $annotationManager)
  70      {
  71          if (($docComment = $this->getDocComment()) == '') {
  72              return false;
  73          }
  74  
  75          if ($this->annotations) {
  76              return $this->annotations;
  77          }
  78  
  79          $cachingFileScanner = $this->createFileScanner($this->getFileName());
  80          $nameInformation    = $cachingFileScanner->getClassNameInformation($this->getDeclaringClass()->getName());
  81  
  82          if (! $nameInformation) {
  83              return false;
  84          }
  85  
  86          $this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
  87  
  88          return $this->annotations;
  89      }
  90  
  91      /**
  92       * Get start line (position) of method
  93       *
  94       * @param  bool $includeDocComment
  95       * @return int
  96       */
  97      public function getStartLine($includeDocComment = false)
  98      {
  99          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  }


Generated: Wed Nov 11 20:28:18 2020 Cross-referenced by PHPXref 0.7.1