static function getObjectProperties($object, bool $includeStatic = true): array
    {
        $properties = [];

        try {
            $filter =
                \ReflectionProperty::IS_PUBLIC
                | \ReflectionProperty::IS_PROTECTED
                | \ReflectionProperty::IS_PRIVATE;

            $parentFilter = \ReflectionProperty::IS_PRIVATE; // only fetch private parent properties

            $reflection = new \ReflectionObject($object);
            foreach ($reflection->getProperties($filter) as $property) {
                if (!$includeStatic && $property->isStatic()) {
                    continue;
                }

                $properties[$property->getName()] = $property;
            }

            foreach (class_parents($object) as $parentClass) {
                $reflection = new \ReflectionClass($parentClass);

                foreach ($reflection->getProperties($parentFilter) as $property) {
                    if (
                        ($includeStatic || !$property->isStatic())
                        && !key_exists($name = $property->getName(), $properties)
                    ) {
                        $properties[$name] = $property;
                    }
                }
            }
        } catch (\ReflectionException $e) {
            // some objects may not be fully accessible (e.g. instances of internal classes)
        }

        return $properties;
    }