$names * @return list At most $limit names. */ public static function similar(string $name, array $names, int $limit = 5): array { $needle = mb_strtolower(trim($name)); if ($needle === '' || $limit < 1) { return []; } $maxDistance = max(3, intdiv(mb_strlen($needle), 3)); $ranked = []; foreach (array_unique($names) as $candidate) { $lower = mb_strtolower($candidate); $distance = levenshtein($needle, $lower); $rank = match (true) { $lower === $needle => 0, str_starts_with($lower, $needle) => 1, str_contains($lower, $needle) => 2, $distance <= $maxDistance => 3, default => null, }; if ($rank !== null) { $ranked[] = [$rank, $distance, mb_strlen($candidate), $candidate]; } } usort($ranked, static fn (array $a, array $b): int => $a[0] <=> $b[0] ?: $a[1] <=> $b[1] ?: $a[2] <=> $b[2] ?: strcmp($a[3], $b[3])); return array_slice(array_column($ranked, 3), 0, $limit); } }