public static function getProperties($source, $filter = null, $includeParents = false): array
    {
        $className = self::getClassName($source);
        $reflection = new \ReflectionClass($className);

        if (null === $filter) {
            $filter = \ReflectionProperty::IS_PRIVATE
                + \ReflectionProperty::IS_PROTECTED
                + \ReflectionProperty::IS_PUBLIC
                + \ReflectionProperty::IS_STATIC;
        }

        $properties = $reflection->getProperties($filter);
        $parentProperties = [];

        if ($includeParents) {
            $parent = self::getParentClass($source);

            if (false !== $parent) {
                $parentClass = $parent->getName();
                $parentProperties = self::getProperties($parentClass, $filter, $includeParents);
            }
        }

        return array_merge($properties, $parentProperties);
    }