private static function canReturnArraysByReference(ArrayAccess $obj, $key, &$value, &$ex)
    {
        static $supportedClasses = [
            // Add our classes by default to help with performance since we can
            Bag::class                     => true, // but deprecated
            MutableBag::class              => true,

            // These fail reflection check below even though they work fine :rolleyes:
            \ArrayObject::class            => true,
            \ArrayIterator::class          => true,
            \RecursiveArrayIterator::class => true,
        ];
        static $noErrors = [];

        $class = get_class($obj);

        /*
         * Check to see if offsetGet() is defined to return reference (with "&" before method name).
         * This prevents us from triggering indirect modification notices.
         * We know for sure that the method cannot return by reference if not defined correctly, so we cache false.
         * We do not know for sure that the method can return by reference if it is defined correctly, so we cache
         * null instead of true. This allows the reflection check to only happen once, but still drop through to
         * validation below.
         */
        if (!isset($supportedClasses[$class])) {
            $supportedClasses[$class] = (new \ReflectionMethod($obj, 'offsetGet'))->returnsReference() ? null : false;
        }

        // If definite value return that, else run validation below.
        if ($supportedClasses[$class] !== null) {
            return $supportedClasses[$class];
        }

        if (isset($noErrors[$class])) {
            $value1 = &$obj[$key];
        } else {
            Thrower::set();
            try {
                $value1 = &$obj[$key];
            } catch (\ErrorException $e) {
                $msg = $e->getMessage();
                if ($msg === 'Only variable references should be returned by reference' ||
                    strpos($msg, 'Indirect modification of overloaded element') === 0
                ) {
                    $ex = $e;

                    return $supportedClasses[$class] = false;
                }
                throw $e;
            } finally {
                restore_error_handler();
            }

            // We assume the object is not going to trigger warnings at this point
            $noErrors[$class] = true;
        }

        // We cannot validate this result because objects are always returned by reference (and scalars do not matter).
        if (!is_array($value1)) {
            // return value (via parameter) so set() doesn't have to fetch the item again.
            // We cannot do this if is an array because it will be the value instead of the reference.
            $value = $value1;

            return true;
        }

        // Verify the object can return arrays by reference.
        $value2 = &$obj[$key];
        $testKey = uniqid('__reference_test_');
        $value1[$testKey] = 'test';
        $supportedClasses[$class] = isset($value2[$testKey]);
        unset($value1[$testKey]);

        return $supportedClasses[$class];
    }