Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • ArrayHash
  • ArrayList
  • Arrays
  • Callback
  • DateTime
  • FileSystem
  • Finder
  • Html
  • Image
  • Json
  • ObjectHelpers
  • ObjectMixin
  • Paginator
  • Random
  • Reflection
  • SafeStream
  • Strings
  • TokenIterator
  • Tokenizer
  • Validators

Interfaces

  • IHtmlString

Exceptions

  • AssertionException
  • ImageException
  • JsonException
  • RegexpException
  • TokenizerException
  • UnknownImageFileException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Utils;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * PHP reflection helpers.
 15:  */
 16: class Reflection
 17: {
 18:     use Nette\StaticClass;
 19: 
 20:     private static $builtinTypes = [
 21:         'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
 22:         'callable' => 1, 'iterable' => 1, 'void' => 1,
 23:     ];
 24: 
 25: 
 26:     /**
 27:      * @param  string
 28:      * @return bool
 29:      */
 30:     public static function isBuiltinType($type)
 31:     {
 32:         return isset(self::$builtinTypes[strtolower($type)]);
 33:     }
 34: 
 35: 
 36:     /**
 37:      * @return string|null
 38:      */
 39:     public static function getReturnType(\ReflectionFunctionAbstract $func)
 40:     {
 41:         return PHP_VERSION_ID >= 70000 && $func->hasReturnType()
 42:             ? self::normalizeType($func->getReturnType(), $func)
 43:             : null;
 44:     }
 45: 
 46: 
 47:     /**
 48:      * @return string|null
 49:      */
 50:     public static function getParameterType(\ReflectionParameter $param)
 51:     {
 52:         if (PHP_VERSION_ID >= 70000) {
 53:             return $param->hasType()
 54:                 ? self::normalizeType($param->getType(), $param)
 55:                 : null;
 56:         } elseif ($param->isArray() || $param->isCallable()) {
 57:             return $param->isArray() ? 'array' : 'callable';
 58:         } else {
 59:             try {
 60:                 return ($ref = $param->getClass()) ? $ref->getName() : null;
 61:             } catch (\ReflectionException $e) {
 62:                 if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
 63:                     return $m[1];
 64:                 }
 65:                 throw $e;
 66:             }
 67:         }
 68:     }
 69: 
 70: 
 71:     private static function normalizeType($type, $reflection)
 72:     {
 73:         $type = PHP_VERSION_ID >= 70100 ? $type->getName() : (string) $type;
 74:         $lower = strtolower($type);
 75:         if ($lower === 'self') {
 76:             return $reflection->getDeclaringClass()->getName();
 77:         } elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) {
 78:             return $reflection->getDeclaringClass()->getParentClass()->getName();
 79:         } else {
 80:             return $type;
 81:         }
 82:     }
 83: 
 84: 
 85:     /**
 86:      * @return mixed
 87:      * @throws \ReflectionException when default value is not available or resolvable
 88:      */
 89:     public static function getParameterDefaultValue(\ReflectionParameter $param)
 90:     {
 91:         if ($param->isDefaultValueConstant()) {
 92:             $const = $orig = $param->getDefaultValueConstantName();
 93:             $pair = explode('::', $const);
 94:             if (isset($pair[1]) && strtolower($pair[0]) === 'self') {
 95:                 $pair[0] = $param->getDeclaringClass()->getName();
 96:             }
 97:             if (isset($pair[1]) && PHP_VERSION_ID >= 70100) {
 98:                 try {
 99:                     $rcc = new \ReflectionClassConstant($pair[0], $pair[1]);
100:                 } catch (\ReflectionException $e) {
101:                     $name = self::toString($param);
102:                     throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name.", 0, $e);
103:                 }
104:                 return $rcc->getValue();
105:             }
106:             $const = implode('::', $pair);
107:             if (!defined($const)) {
108:                 $const = substr((string) strrchr($const, '\\'), 1);
109:                 if (isset($pair[1]) || !defined($const)) {
110:                     $name = self::toString($param);
111:                     throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name.");
112:                 }
113:             }
114:             return constant($const);
115:         }
116:         return $param->getDefaultValue();
117:     }
118: 
119: 
120:     /**
121:      * Returns declaring class or trait.
122:      * @return \ReflectionClass
123:      */
124:     public static function getPropertyDeclaringClass(\ReflectionProperty $prop)
125:     {
126:         foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
127:             if ($trait->hasProperty($prop->getName())) {
128:                 return self::getPropertyDeclaringClass($trait->getProperty($prop->getName()));
129:             }
130:         }
131:         return $prop->getDeclaringClass();
132:     }
133: 
134: 
135:     /**
136:      * Are documentation comments available?
137:      * @return bool
138:      */
139:     public static function areCommentsAvailable()
140:     {
141:         static $res;
142:         return $res === null
143:             ? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment()
144:             : $res;
145:     }
146: 
147: 
148:     /**
149:      * @return string
150:      */
151:     public static function toString(\Reflector $ref)
152:     {
153:         if ($ref instanceof \ReflectionClass) {
154:             return $ref->getName();
155:         } elseif ($ref instanceof \ReflectionMethod) {
156:             return $ref->getDeclaringClass()->getName() . '::' . $ref->getName();
157:         } elseif ($ref instanceof \ReflectionFunction) {
158:             return $ref->getName();
159:         } elseif ($ref instanceof \ReflectionProperty) {
160:             return self::getPropertyDeclaringClass($ref)->getName() . '::$' . $ref->getName();
161:         } elseif ($ref instanceof \ReflectionParameter) {
162:             return '$' . $ref->getName() . ' in ' . self::toString($ref->getDeclaringFunction()) . '()';
163:         } else {
164:             throw new Nette\InvalidArgumentException;
165:         }
166:     }
167: 
168: 
169:     /**
170:      * Expands class name into full name.
171:      * @param  string
172:      * @return string  full name
173:      * @throws Nette\InvalidArgumentException
174:      */
175:     public static function expandClassName($name, \ReflectionClass $rc)
176:     {
177:         $lower = strtolower($name);
178:         if (empty($name)) {
179:             throw new Nette\InvalidArgumentException('Class name must not be empty.');
180: 
181:         } elseif (isset(self::$builtinTypes[$lower])) {
182:             return $lower;
183: 
184:         } elseif ($lower === 'self') {
185:             return $rc->getName();
186: 
187:         } elseif ($name[0] === '\\') { // fully qualified name
188:             return ltrim($name, '\\');
189:         }
190: 
191:         $uses = self::getUseStatements($rc);
192:         $parts = explode('\\', $name, 2);
193:         if (isset($uses[$parts[0]])) {
194:             $parts[0] = $uses[$parts[0]];
195:             return implode('\\', $parts);
196: 
197:         } elseif ($rc->inNamespace()) {
198:             return $rc->getNamespaceName() . '\\' . $name;
199: 
200:         } else {
201:             return $name;
202:         }
203:     }
204: 
205: 
206:     /**
207:      * @return array of [alias => class]
208:      */
209:     public static function getUseStatements(\ReflectionClass $class)
210:     {
211:         static $cache = [];
212:         if (!isset($cache[$name = $class->getName()])) {
213:             if ($class->isInternal()) {
214:                 $cache[$name] = [];
215:             } else {
216:                 $code = file_get_contents($class->getFileName());
217:                 $cache = self::parseUseStatements($code, $name) + $cache;
218:             }
219:         }
220:         return $cache[$name];
221:     }
222: 
223: 
224:     /**
225:      * Parses PHP code.
226:      * @param  string
227:      * @return array of [class => [alias => class, ...]]
228:      */
229:     private static function parseUseStatements($code, $forClass = null)
230:     {
231:         $tokens = PHP_VERSION_ID >= 70000 ? token_get_all($code, TOKEN_PARSE) : token_get_all($code);
232:         $namespace = $class = $classLevel = $level = null;
233:         $res = $uses = [];
234: 
235:         while ($token = current($tokens)) {
236:             next($tokens);
237:             switch (is_array($token) ? $token[0] : $token) {
238:                 case T_NAMESPACE:
239:                     $namespace = ltrim(self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
240:                     $uses = [];
241:                     break;
242: 
243:                 case T_CLASS:
244:                 case T_INTERFACE:
245:                 case T_TRAIT:
246:                     if ($name = self::fetch($tokens, T_STRING)) {
247:                         $class = $namespace . $name;
248:                         $classLevel = $level + 1;
249:                         $res[$class] = $uses;
250:                         if ($class === $forClass) {
251:                             return $res;
252:                         }
253:                     }
254:                     break;
255: 
256:                 case T_USE:
257:                     while (!$class && ($name = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]))) {
258:                         $name = ltrim($name, '\\');
259:                         if (self::fetch($tokens, '{')) {
260:                             while ($suffix = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR])) {
261:                                 if (self::fetch($tokens, T_AS)) {
262:                                     $uses[self::fetch($tokens, T_STRING)] = $name . $suffix;
263:                                 } else {
264:                                     $tmp = explode('\\', $suffix);
265:                                     $uses[end($tmp)] = $name . $suffix;
266:                                 }
267:                                 if (!self::fetch($tokens, ',')) {
268:                                     break;
269:                                 }
270:                             }
271: 
272:                         } elseif (self::fetch($tokens, T_AS)) {
273:                             $uses[self::fetch($tokens, T_STRING)] = $name;
274: 
275:                         } else {
276:                             $tmp = explode('\\', $name);
277:                             $uses[end($tmp)] = $name;
278:                         }
279:                         if (!self::fetch($tokens, ',')) {
280:                             break;
281:                         }
282:                     }
283:                     break;
284: 
285:                 case T_CURLY_OPEN:
286:                 case T_DOLLAR_OPEN_CURLY_BRACES:
287:                 case '{':
288:                     $level++;
289:                     break;
290: 
291:                 case '}':
292:                     if ($level === $classLevel) {
293:                         $class = $classLevel = null;
294:                     }
295:                     $level--;
296:             }
297:         }
298: 
299:         return $res;
300:     }
301: 
302: 
303:     private static function fetch(&$tokens, $take)
304:     {
305:         $res = null;
306:         while ($token = current($tokens)) {
307:             list($token, $s) = is_array($token) ? $token : [$token, $token];
308:             if (in_array($token, (array) $take, true)) {
309:                 $res .= $s;
310:             } elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], true)) {
311:                 break;
312:             }
313:             next($tokens);
314:         }
315:         return $res;
316:     }
317: }
318: 
Nette 2.4-20191120 API API documentation generated by ApiGen 2.8.0