Repository: symfony/symfony
File: src/Symfony/Component/OptionsResolver/OptionsResolver.php (PHP)

Code before:
            }

            return $valid;
        }

        if (('null' === $type && null === $value) || (isset(self::VALIDATION_FUNCTIONS[$type]) ? self::VALIDATION_FUNCTIONS[$type]($value) : $value instanceof $type)) {
            return true;
        }

        if (\is_array($invalidTypes) && (!$invalidTypes || $level > 0)) {
            $invalidTypes[get_debug_type($value)] = true;
        }

        return false;
    }

    /**
     * @return list<string>
     */
    private function splitOutsideParenthesis(string $type): array
    {
        if (!str_contains($type, '|')) {
            return [$type];
        }

        if (!str_contains($type, '(') && !str_contains($type, ')')) {
            return explode('|', $type);
        }

        $parts = [];
        $start = 0;
        $parenthesisLevel = 0;
        $length = \strlen($type);

        for ($i = 0; $i < $length; ++$i) {
            $char = $type[$i];

            switch ($char) {
                case '(':
                    ++$parenthesisLevel;
                    break;
                case ')':
                    --$parenthesisLevel;
                    break;
                case '|':
                    if (0 === $parenthesisLevel) {
                        $parts[] = substr($type, $start, $i - $start);
                        $start = $i + 1;
                    }
                    break;
            }

Review comment (performance):
We could likely optimize that too by looping over characters and check for both parenthesis. This will prevent looping two times.

A regexp to avoid the two calls to `str_contains()` may also be faster than the current implementation (but slower that the loop I propose).

Code after:
            }

            return $valid;
        }

        if (('null' === $type && null === $value) || (isset(self::VALIDATION_FUNCTIONS[$type]) ? self::VALIDATION_FUNCTIONS[$type]($value) : $value instanceof $type)) {
            return true;
        }

        if (\is_array($invalidTypes) && (!$invalidTypes || $level > 0)) {
            $invalidTypes[get_debug_type($value)] = true;
        }

        return false;
    }

    /**
     * @return list<string>
     */
    private function splitOutsideParenthesis(string $type): array
    {
        return preg_split(<<<'EOF'
                /
                # Define a recursive subroutine for matching balanced parentheses
                (?(DEFINE)
                    (?<balanced>
                        \(                          # Match an opening parenthesis
                        (?:                         # Start a non-capturing group for the contents
                            [^()]                   # Match any character that is not a parenthesis
                            |                       # OR
                            (?&balanced)            # Recursively match a nested balanced group
                        )*                          # Repeat the group for all contents
                        \)                          # Match the final closing parenthesis
                    )
                )

                # Match any balanced parenthetical group, then skip it
                (?&balanced)(*SKIP)(*FAIL)          # Use the defined subroutine and discard the match

                | # OR

                \|                                  # Match the pipe delimiter (only if not inside a skipped group)
                /x
        EOF, $type);
    }

    /**
     * Returns whether a resolved option with the given name exists.
     *
     * @throws AccessException If accessing this method outside of {@link resolve()}
     *