public static function info($identifier, $info = []) {
		$info = $info ?: array_keys(static::$_methodMap);
		$type = static::type($identifier);
		$result = [];
		$class = null;

		if ($type === 'method' || $type === 'property') {
			list($class, $identifier) = explode('::', $identifier);

			try {
				$classInspector = new ReflectionClass($class);
			} catch (Exception $e) {
				return null;
			}

			if ($type === 'property') {
				$identifier = substr($identifier, 1);
				$accessor = 'getProperty';
			} else {
				$identifier = str_replace('()', '', $identifier);
				$accessor = 'getMethod';
			}

			try {
				$inspector = $classInspector->{$accessor}($identifier);
			} catch (Exception $e) {
				return null;
			}
			$result['modifiers'] = static::_modifiers($inspector);
		} elseif ($type === 'class') {
			$inspector = new ReflectionClass($identifier);
			$classInspector = null;
		} else {
			return null;
		}

		foreach ($info as $key) {
			if (!isset(static::$_methodMap[$key])) {
				continue;
			}
			if (method_exists($inspector, static::$_methodMap[$key])) {
				$setAccess = (
					($type === 'method' || $type === 'property') &&
					array_intersect($result['modifiers'], ['private', 'protected']) !== [] &&
					method_exists($inspector, 'setAccessible')
				);

				if ($setAccess) {
					$inspector->setAccessible(true);
				}
				$result[$key] = $inspector->{static::$_methodMap[$key]}();

				if ($setAccess) {
					$inspector->setAccessible(false);
				}
			}
		}

		if ($type === 'property' && $classInspector && !$classInspector->isAbstract()) {
			$inspector->setAccessible(true);

			try {
				$result['value'] = $inspector->getValue(static::_class($class));
			} catch (Exception $e) {
				return null;
			}
		}

		if (isset($result['start']) && isset($result['end'])) {
			$result['length'] = $result['end'] - $result['start'];
		}
		if (isset($result['comment'])) {
			$result += Docblock::comment($result['comment']);
		}
		return $result;
	}