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
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

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