Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:03 - 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