public static function setProperty(&$subject, $propertyName, $propertyValue, bool $forceDirectAccess = false): bool
    {
        if (is_array($subject)) {
            $subject[$propertyName] = $propertyValue;
            return true;
        }

        if (!is_object($subject)) {
            throw new \InvalidArgumentException('subject must be an object or array, ' . gettype($subject) . ' given.', 1237301368);
        }
        if (!is_string($propertyName) && !is_int($propertyName)) {
            throw new \InvalidArgumentException('Given property name/index is not of type string or integer.', 1231178878);
        }

        if ($forceDirectAccess === true) {
            $className = TypeHandling::getTypeForValue($subject);
            if (property_exists($className, $propertyName)) {
                $propertyReflection = new \ReflectionProperty($className, $propertyName);
                $propertyReflection->setAccessible(true);
                $propertyReflection->setValue($subject, $propertyValue);
            } else {
                $subject->$propertyName = $propertyValue;
            }
        } elseif (is_callable([$subject, $setterMethodName = self::buildSetterMethodName($propertyName)])) {
            $subject->$setterMethodName($propertyValue);
        } elseif ($subject instanceof \ArrayAccess) {
            $subject[$propertyName] = $propertyValue;
        } elseif (array_key_exists($propertyName, get_object_vars($subject))) {
            $subject->$propertyName = $propertyValue;
        } else {
            return false;
        }
        return true;
    }