protected static function getPropertyInternal($subject, string $propertyName, bool $forceDirectAccess, bool &$propertyExists)
    {
        if ($subject === null) {
            return null;
        }
        if (is_array($subject)) {
            $propertyExists = array_key_exists($propertyName, $subject);
            return $propertyExists ? $subject[$propertyName] : null;
        }
        if (!is_object($subject)) {
            return null;
        }

        $propertyExists = true;
        $className = TypeHandling::getTypeForValue($subject);

        if ($forceDirectAccess === true) {
            if (property_exists($className, $propertyName)) {
                $propertyReflection = new \ReflectionProperty($className, $propertyName);
                $propertyReflection->setAccessible(true);
                return $propertyReflection->getValue($subject);
            }
            if (property_exists($subject, $propertyName)) {
                return $subject->$propertyName;
            }
            throw new PropertyNotAccessibleException('The property "' . $propertyName . '" on the subject does not exist.', 1302855001);
        }

        if ($subject instanceof \stdClass) {
            if (array_key_exists($propertyName, get_object_vars($subject))) {
                return $subject->$propertyName;
            }
            $propertyExists = false;
            return null;
        }

        $cacheIdentifier = $className . '|' . $propertyName;
        self::initializePropertyGetterCache($cacheIdentifier, $subject, $propertyName);

        if (isset(self::$propertyGetterCache[$cacheIdentifier]['accessorMethod'])) {
            $method = self::$propertyGetterCache[$cacheIdentifier]['accessorMethod'];
            return $subject->$method();
        }
        if (isset(self::$propertyGetterCache[$cacheIdentifier]['publicProperty'])) {
            return $subject->$propertyName;
        }

        if (($subject instanceof \ArrayAccess) && !($subject instanceof \SplObjectStorage) && $subject->offsetExists($propertyName)) {
            return $subject->offsetGet($propertyName);
        }

        $propertyExists = false;
        return null;
    }