Install the package:
composer require open-feature/flagd-provider
Configure OpenFeature:
use OpenFeature\FlagdProvider\FlagdProvider;
use OpenFeature\OpenFeature;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
// Initialize HTTP client (e.g., Guzzle)
$client = new \GuzzleHttp\Client();
$requestFactory = \GuzzleHttp\Psr7\RequestFactory::create($client);
// Initialize FlagdProvider
$flagdProvider = new FlagdProvider(
$client,
$requestFactory,
host: 'localhost',
port: 8013,
scheme: 'http'
);
// Register with OpenFeature
OpenFeature::setProvider($flagdProvider);
First Use Case:
// Evaluate a flag
$flagValue = OpenFeature::getFlag('my-feature-flag', false);
// Or with context
$context = new \OpenFeature\Context(Context::create('user', ['id' => '123']));
$flagValue = OpenFeature::getFlag('my-feature-flag', false, $context);
src/FlagdProvider.php: Core provider logic.src/Exceptions/FlagdProviderException.php: Error handling.tests/: Integration tests for edge cases.Dynamic Feature Toggles:
// Toggle a feature based on user segment
$context = Context::create('user', ['segment' => 'premium']);
$isEnabled = OpenFeature::getFlag('premium-feature', false, $context);
Gradual Rollouts:
// Rollout to 10% of users
$context = Context::create('user', ['id' => 'user-42']);
$isEnabled = OpenFeature::getFlag('experimental-feature', false, $context, 0.1);
Fallback Logic:
// Default to false if Flagd is unreachable
$isEnabled = OpenFeature::getFlag('critical-feature', true, $context);
Dependency Injection:
Bind FlagdProvider in your DI container (e.g., Laravel’s AppServiceProvider):
$this->app->bind(FlagdProvider::class, function ($app) {
return new FlagdProvider(
$app->make(\GuzzleHttp\Client::class),
$app->make(\GuzzleHttp\Psr7\RequestFactory::class),
host: config('services.flagd.host')
);
});
Context Management: Reuse contexts across flag evaluations to avoid redundant payloads:
$userContext = Context::create('user', ['id' => '123']);
$flag1 = OpenFeature::getFlag('feature-a', false, $userContext);
$flag2 = OpenFeature::getFlag('feature-b', false, $userContext);
Async Evaluation (if using async HTTP clients):
$promise = OpenFeature::getFlagAsync('async-feature', false, $context);
$promise->then(fn($value) => logger()->info("Flag value: {$value}"));
Connection Issues:
FlagdProviderException on HTTP failures. Handle gracefully:
try {
$value = OpenFeature::getFlag('feature', false);
} catch (FlagdProviderException $e) {
logger()->error("Flagd unavailable, using fallback: {$e->getMessage()}");
return false; // Fallback
}
retry helper or a circuit breaker (e.g., spatie/laravel-circuitbreaker) for transient failures.Schema Mismatches:
flagd.yaml) against the spec to avoid InvalidFlagDefinition errors.Context Overhead:
user.id instead of full user object).Caching:
Cache facade):
$cacheKey = "feature:{$flagName}:".json_encode($context->toArray());
return Cache::remember($cacheKey, now()->addMinutes(5), function() use ($flagName, $context) {
return OpenFeature::getFlag($flagName, false, $context);
});
Enable Logging: Inject a PSR-3 logger to debug FlagdProvider:
$flagdProvider = new FlagdProvider($client, $requestFactory, [
'logger' => new \Monolog\Logger('flagd'),
]);
Logs will include HTTP requests/responses and flag evaluations.
Flagd CLI: Test Flagd locally with:
flagd --config=flagd.yaml --log-level=debug
Custom Providers:
Combine with other providers (e.g., OpenFeature\NoOpProvider) for hybrid setups:
OpenFeature::setProvider(new \OpenFeature\CompositeProvider([
new FlagdProvider($client, $requestFactory),
new \OpenFeature\NoOpProvider(), // Fallback
]));
Middleware: Add request/response middleware to modify Flagd payloads:
$stack = \Http\Message\Middleware::create();
$stack->push(\OpenFeature\FlagdProvider\Middleware\AddHeader::class, 'X-Custom-Header', 'value');
$client = new \GuzzleHttp\Client(['handler' => $stack]);
Testing:
Mock FlagdProvider in tests using OpenFeature\MockProvider:
OpenFeature::setProvider(new \OpenFeature\MockProvider());
OpenFeature::getFlag('test-flag')->shouldReturn(true);
How can I help you explore Laravel packages today?