transformedFilters)) { return $this->transformedFilters[$value]; } [$pattern, $replacement] = $this->getPatternAndReplacement(); $filtered = preg_replace($pattern, $replacement, $value); $lowerFunction = $this->getLowerFunction(); /** @var string $filteredValue */ $filteredValue = $lowerFunction($filtered); $this->transformedFilters[$value] = $filteredValue; return $filteredValue; } /** * @return non-empty-string[][] Array with two elements, first the patterns, then the * replacements. Each element is an array of strings. */ private function getPatternAndReplacement(): array { return $this->hasPcreUnicodeSupport() ? [ [ // pattern '#(?<=(?:\p{Lu}))(\p{Lu}\p{Ll})#', '#(?<=(?:\p{Ll}|\p{Nd}))(\p{Lu})#', ], [ // replacement '_\1', '_\1', ], ] : [ [ // pattern '#(?<=(?:[A-Z]))([A-Z]+)([A-Z][a-z])#', '#(?<=(?:[a-z0-9]))([A-Z])#', ], [ // replacement '\1_\2', '_\1', ], ]; } private function getLowerFunction(): callable { return $this->hasMbStringSupport() ? static fn($value): string => // ignore unicode characters w/ strtolower mb_strtolower($value, 'UTF-8') : static fn($value) => preg_replace_callback('#([A-Z])#', static fn($matches): string => strtolower($matches[1]), $value); } }