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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Tiered scoring lets you prefer exact and prefix matches while still tolerating typos as a fallback.
- 2Normalizing case and whitespace once up front keeps every comparison consistent.
- 3Separating scoring from selection keeps the ranking logic testable and easy to tune.
Related explainers
php
<?php namespace App\Models;
Debouncing Eloquent jobs in Laravel
debounce
model-events
queued-jobs
Advanced
7 steps
php
<?php namespace App\Http\Controllers\Api;
Cursor pagination in a Laravel API
pagination
cursor
keyset
Intermediate
9 steps
python
from difflib import SequenceMatcher from bisect import bisect_left, bisect_right
Building a fuzzy autocomplete matcher
fuzzy-matching
binary-search
ranking
Intermediate
9 steps
php
<?php namespace App\Queue;
A stable priority job queue in PHP
priority-queue
data-structures
closures
Intermediate
8 steps
php
<?php namespace App\Support;
Normalizing phone numbers to E.164 in PHP
input-validation
normalization
regular-expressions
Intermediate
8 steps
php
final class Route { private string $regex; private array $paramNames = [];
Compiling route patterns into regex in PHP
routing
regex
parsing
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-ranked-fuzzy-search-in-php-explained-php-836a/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.