php
58 lines · 8 steps
How a feature flag evaluator decides
A flag evaluator resolves an on/off decision from static config, targeting rules, and a stable percentage rollout.
Explained by
highlit
1<?php
2
3namespace App\FeatureFlags;
4
5class FlagEvaluator
6{
7 public function __construct(private array $flags)
8 {
9 }
10
11 public function isEnabled(string $flag, array $context = []): bool
12 {
13 $config = $this->flags[$flag] ?? null;
14
15 if ($config === null || ($config['enabled'] ?? false) === false) {
16 return false;
17 }
18
19 foreach ($config['rules'] ?? [] as $rule) {
20 if ($this->matchesRule($rule, $context)) {
21 return $rule['serve'] ?? true;
22 }
23 }
24
25 $rollout = $config['rollout'] ?? 100;
26
27 return $this->withinRollout($flag, $context['user_id'] ?? '', $rollout);
28 }
29
30 private function matchesRule(array $rule, array $context): bool
31 {
32 $value = $context[$rule['attribute']] ?? null;
33
34 return match ($rule['operator']) {
35 'in' => in_array($value, $rule['values'], true),
36 'not_in' => !in_array($value, $rule['values'], true),
37 'equals' => $value === $rule['value'],
38 'greater_than' => is_numeric($value) && $value > $rule['value'],
39 'ends_with' => is_string($value) && str_ends_with($value, $rule['value']),
40 default => false,
41 };
42 }
43
44 private function withinRollout(string $flag, string $userId, int $percentage): bool
45 {
46 if ($percentage >= 100) {
47 return true;
48 }
49
50 if ($percentage <= 0 || $userId === '') {
51 return false;
52 }
53
54 $bucket = crc32($flag . ':' . $userId) % 100;
55
56 return $bucket < $percentage;
57 }
58}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Layering a global switch, targeting rules, and a percentage rollout lets one method serve nuanced flag decisions.
- 2Hashing a stable key like flag plus user id gives consistent bucketing so a user always lands the same way.
- 3The null-coalescing operator and match expression keep config-driven logic terse and safe against missing keys.
Related explainers
php
<?php declare(strict_types=1);
Normalizing human names in PHP
unicode
text-normalization
transliteration
Intermediate
8 steps
php
<?php namespace App\Http\Controllers;
Handling Stripe webhooks in Laravel
webhooks
signature-verification
dependency-injection
Intermediate
7 steps
php
namespace App\Providers; use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider;
Building a @money Blade directive in Laravel
blade-directive
service-provider
localization
Intermediate
5 steps
php
<?php namespace App\Queue;
Deduplicating a job queue with Redis
deduplication
redis
atomicity
Advanced
8 steps
php
<?php namespace App\Providers;
Defining authorization gates in Laravel
authorization
gates
service-provider
Intermediate
6 steps
php
<?php final class TaskProgressReporter {
Tracking task progress in a JSON file
state-persistence
atomic-writes
json
Intermediate
9 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/how-a-feature-flag-evaluator-decides-explained-php-a9e7/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.