public static function properties($class, array $options = []) {
		$defaults = ['properties' => [], 'self' => true];
		$options += $defaults;

		try {
			$reflClass = new ReflectionClass($class);
		} catch (ReflectionException $e) {
			return null;
		}
		$options += ['names' => $options['properties']];

		return static::_items($reflClass, 'getProperties', $options)->map(function($item) use ($class) {
			$modifiers = array_values(Inspector::invokeMethod('_modifiers', [$item]));
			$setAccess = (
				array_intersect($modifiers, ['private', 'protected']) !== []
			);
			if ($setAccess) {
				$item->setAccessible(true);
			}
			if (is_string($class)) {
				if (!$item->isStatic()) {
					$message = 'Must provide an object instance for non-static properties.';
					throw new InvalidArgumentException($message);
				}
				$value = $item->getValue($item->getDeclaringClass());
			} else {
				$value = $item->getValue($class);
			}
			$result = compact('modifiers', 'value') + [
				'docComment' => $item->getDocComment(),
				'name' => $item->getName()
			];
			if ($setAccess) {
				$item->setAccessible(false);
			}
			return $result;
		}, ['collect' => false]);
	}