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
  • Other releases
  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((string) $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((string) $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:         $lower = strtolower($type);
 74:         if ($lower === 'self') {
 75:             return $reflection->getDeclaringClass()->getName();
 76:         } elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) {
 77:             return $reflection->getDeclaringClass()->getParentClass()->getName();
 78:         } else {
 79:             return $type;
 80:         }
 81:     }
 82: 
 83: 
 84:     /**
 85:      * @return mixed
 86:      * @throws \ReflectionException when default value is not available or resolvable
 87:      */
 88:     public static function getParameterDefaultValue(\ReflectionParameter $param)
 89:     {
 90:         if ($param->isDefaultValueConstant()) {
 91:             $const = $orig = $param->getDefaultValueConstantName();
 92:             $pair = explode('::', $const);
 93:             if (isset($pair[1]) && strtolower($pair[0]) === 'self') {
 94:                 $pair[0] = $param->getDeclaringClass()->getName();
 95:             }
 96:             if (isset($pair[1]) && PHP_VERSION_ID >= 70100) {
 97:                 try {
 98:                     $rcc = new \ReflectionClassConstant($pair[0], $pair[1]);
 99:                 } catch (\ReflectionException $e) {
100:                     $name = self::toString($param);
101:                     throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name.", 0, $e);
102:                 }
103:                 return $rcc->getValue();
104:             }
105:             $const = implode('::', $pair);
106:             if (!defined($const)) {
107:                 $const = substr((string) strrchr($const, '\\'), 1);
108:                 if (isset($pair[1]) || !defined($const)) {
109:                     $name = self::toString($param);
110:                     throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name.");
111:                 }
112:             }
113:             return constant($const);
114:         }
115:         return $param->getDefaultValue();
116:     }
117: 
118: 
119:     /**
120:      * Returns declaring class or trait.
121:      * @return \ReflectionClass
122:      */
123:     public static function getPropertyDeclaringClass(\ReflectionProperty $prop)
124:     {
125:         foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
126:             if ($trait->hasProperty($prop->getName())) {
127:                 return self::getPropertyDeclaringClass($trait->getProperty($prop->getName()));
128:             }
129:         }
130:         return $prop->getDeclaringClass();
131:     }
132: 
133: 
134:     /**
135:      * Are documentation comments available?
136:      * @return bool
137:      */
138:     public static function areCommentsAvailable()
139:     {
140:         static $res;
141:         return $res === null
142:             ? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment()
143:             : $res;
144:     }
145: 
146: 
147:     /**
148:      * @return string
149:      */
150:     public static function toString(\Reflector $ref)
151:     {
152:         if ($ref instanceof \ReflectionClass) {
153:             return $ref->getName();
154:         } elseif ($ref instanceof \ReflectionMethod) {
155:             return $ref->getDeclaringClass()->getName() . '::' . $ref->getName();
156:         } elseif ($ref instanceof \ReflectionFunction) {
157:             return $ref->getName();
158:         } elseif ($ref instanceof \ReflectionProperty) {
159:             return self::getPropertyDeclaringClass($ref)->getName() . '::$' . $ref->getName();
160:         } elseif ($ref instanceof \ReflectionParameter) {
161:             return '$' . $ref->getName() . ' in ' . self::toString($ref->getDeclaringFunction()) . '()';
162:         } else {
163:             throw new Nette\InvalidArgumentException;
164:         }
165:     }
166: 
167: 
168:     /**
169:      * Expands class name into full name.
170:      * @param  string
171:      * @return string  full name
172:      * @throws Nette\InvalidArgumentException
173:      */
174:     public static function expandClassName($name, \ReflectionClass $rc)
175:     {
176:         $lower = strtolower($name);
177:         if (empty($name)) {
178:             throw new Nette\InvalidArgumentException('Class name must not be empty.');
179: 
180:         } elseif (isset(self::$builtinTypes[$lower])) {
181:             return $lower;
182: 
183:         } elseif ($lower === 'self') {
184:             return $rc->getName();
185: 
186:         } elseif ($name[0] === '\\') { // fully qualified name
187:             return ltrim($name, '\\');
188:         }
189: 
190:         $uses = self::getUseStatements($rc);
191:         $parts = explode('\\', $name, 2);
192:         if (isset($uses[$parts[0]])) {
193:             $parts[0] = $uses[$parts[0]];
194:             return implode('\\', $parts);
195: 
196:         } elseif ($rc->inNamespace()) {
197:             return $rc->getNamespaceName() . '\\' . $name;
198: 
199:         } else {
200:             return $name;
201:         }
202:     }
203: 
204: 
205:     /**
206:      * @return array of [alias => class]
207:      */
208:     public static function getUseStatements(\ReflectionClass $class)
209:     {
210:         static $cache = [];
211:         if (!isset($cache[$name = $class->getName()])) {
212:             if ($class->isInternal()) {
213:                 $cache[$name] = [];
214:             } else {
215:                 $code = file_get_contents($class->getFileName());
216:                 $cache = self::parseUseStatements($code, $name) + $cache;
217:             }
218:         }
219:         return $cache[$name];
220:     }
221: 
222: 
223:     /**
224:      * Parses PHP code.
225:      * @param  string
226:      * @return array of [class => [alias => class, ...]]
227:      */
228:     private static function parseUseStatements($code, $forClass = null)
229:     {
230:         $tokens = PHP_VERSION_ID >= 70000 ? token_get_all($code, TOKEN_PARSE) : token_get_all($code);
231:         $namespace = $class = $classLevel = $level = null;
232:         $res = $uses = [];
233: 
234:         while ($token = current($tokens)) {
235:             next($tokens);
236:             switch (is_array($token) ? $token[0] : $token) {
237:                 case T_NAMESPACE:
238:                     $namespace = ltrim(self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
239:                     $uses = [];
240:                     break;
241: 
242:                 case T_CLASS:
243:                 case T_INTERFACE:
244:                 case T_TRAIT:
245:                     if ($name = self::fetch($tokens, T_STRING)) {
246:                         $class = $namespace . $name;
247:                         $classLevel = $level + 1;
248:                         $res[$class] = $uses;
249:                         if ($class === $forClass) {
250:                             return $res;
251:                         }
252:                     }
253:                     break;
254: 
255:                 case T_USE:
256:                     while (!$class && ($name = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]))) {
257:                         $name = ltrim($name, '\\');
258:                         if (self::fetch($tokens, '{')) {
259:                             while ($suffix = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR])) {
260:                                 if (self::fetch($tokens, T_AS)) {
261:                                     $uses[self::fetch($tokens, T_STRING)] = $name . $suffix;
262:                                 } else {
263:                                     $tmp = explode('\\', $suffix);
264:                                     $uses[end($tmp)] = $name . $suffix;
265:                                 }
266:                                 if (!self::fetch($tokens, ',')) {
267:                                     break;
268:                                 }
269:                             }
270: 
271:                         } elseif (self::fetch($tokens, T_AS)) {
272:                             $uses[self::fetch($tokens, T_STRING)] = $name;
273: 
274:                         } else {
275:                             $tmp = explode('\\', $name);
276:                             $uses[end($tmp)] = $name;
277:                         }
278:                         if (!self::fetch($tokens, ',')) {
279:                             break;
280:                         }
281:                     }
282:                     break;
283: 
284:                 case T_CURLY_OPEN:
285:                 case T_DOLLAR_OPEN_CURLY_BRACES:
286:                 case '{':
287:                     $level++;
288:                     break;
289: 
290:                 case '}':
291:                     if ($level === $classLevel) {
292:                         $class = $classLevel = null;
293:                     }
294:                     $level--;
295:             }
296:         }
297: 
298:         return $res;
299:     }
300: 
301: 
302:     private static function fetch(&$tokens, $take)
303:     {
304:         $res = null;
305:         while ($token = current($tokens)) {
306:             list($token, $s) = is_array($token) ? $token : [$token, $token];
307:             if (in_array($token, (array) $take, true)) {
308:                 $res .= $s;
309:             } elseif (!in_array($token, [T_DOC_COMMENT, T_WHITESPACE, T_COMMENT], true)) {
310:                 break;
311:             }
312:             next($tokens);
313:         }
314:         return $res;
315:     }
316: }
317: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0