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