php 53 lines · 7 steps

Building a ranked fuzzy search in PHP

A two-function approach that scores each candidate, filters out non-matches, and returns the best results in order.

Explained by highlit
1function fuzzySearch(string $query, array $items, int $limit = 10): array
2{
3 $query = mb_strtolower(trim($query));
4 
5 if ($query === '') {
6 return array_slice($items, 0, $limit);
7 }
8 
9 $scored = [];
10 
11 foreach ($items as $item) {
12 $candidate = mb_strtolower($item);
13 $score = scoreMatch($query, $candidate);
14 
15 if ($score > 0) {
16 $scored[] = ['item' => $item, 'score' => $score];
17 }
18 }
19 
20 usort($scored, static fn ($a, $b) => $b['score'] <=> $a['score']);
21 
22 return array_map(
23 static fn ($entry) => $entry['item'],
24 array_slice($scored, 0, $limit)
25 );
26}
27 
28function scoreMatch(string $query, string $candidate): float
29{
30 if ($candidate === $query) {
31 return 100.0;
32 }
33 
34 if (str_starts_with($candidate, $query)) {
35 return 90.0 + (strlen($query) / max(strlen($candidate), 1)) * 5;
36 }
37 
38 if (str_contains($candidate, $query)) {
39 return 70.0 + (strlen($query) / max(strlen($candidate), 1)) * 5;
40 }
41 
42 $distance = levenshtein($query, $candidate);
43 $maxLen = max(strlen($query), strlen($candidate), 1);
44 
45 if ($distance > $maxLen * 0.6) {
46 return 0.0;
47 }
48 
49 similar_text($query, $candidate, $percent);
50 $editScore = (1 - $distance / $maxLen) * 40;
51 
52 return round($editScore + $percent * 0.3, 2);
53}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Tiered scoring lets you prefer exact and prefix matches while still tolerating typos as a fallback.
  2. 2Normalizing case and whitespace once up front keeps every comparison consistent.
  3. 3Separating scoring from selection keeps the ranking logic testable and easy to tune.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a ranked fuzzy search in PHP — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code