PHP code example of open-feature / sdk

1. Go to this page and download the library: Download open-feature/sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

open-feature / sdk example snippets


use OpenFeature\OpenFeatureAPI;
use OpenFeature\Providers\Flagd\FlagdProvider;

function example()
{
    $api = OpenFeatureAPI::getInstance();
    
    // configure a provider
    $api->setProvider(new FlagdProvider());

    // create a client
    $client = $api->getClient();
    
    // get a bool flag value
    $client->getBooleanValue('v2_enabled', false);
}

use OpenFeature\OpenFeatureAPI;
use OpenFeature\OpenFeatureClient;

class MyClass 
{
  private OpenFeatureClient $client;

  public function __construct() 
  {
    $this->client = OpenFeatureAPI::getInstance()->getClient('MyClass');
  }

  public function booleanExample(): UI
  {
      // Should we render the redesign? Or the default webpage? 
      if ($this->client->getBooleanValue('redesign_enabled', false)) {
          return render_redesign();
      }
      return render_normal();
  }

  public function stringExample(): Template
  {
      // Get the template to load for the custom new homepage
      $template = $this->client->getStringValue('homepage_template', 'default-homepage.html');

      return render_template($template);
  }

  public function numberExample(): array
  {
      // How many modules should we be fetching?
      $count = $this->client->getIntegerValue('module-fetch-count', 4);

      return fetch_modules($count);
  }

  public function structureExample(): HomepageModule
  {
      $obj = $this->client->getObjectValue('hero-module', $previouslyDefinedDefaultStructure);

      return HomepageModuleBuilder::new()
              ->title($obj->getValue('title'))
              ->body($obj->getValue('description'))
              ->build();
  }
}

$api = OpenFeatureAPI::getInstance();
$api->setProvider(new MyProvider());

use OpenFeature\OpenFeatureAPI;
use OpenFeature\implementation\multiprovider\MultiProvider;

$multiProvider = new MultiProvider([
    ['provider' => new ProviderA()],
    ['provider' => new ProviderB()],
]);

$api = OpenFeatureAPI::getInstance();
$api->setProvider($multiProvider);

$client = $api->getClient();
echo $client->getBooleanValue('my-flag', false);

use OpenFeature\implementation\multiprovider\strategy\FirstSuccessfulStrategy;

$multiProvider = new MultiProvider([
    ['provider' => new ProviderA()],
    ['provider' => new ProviderB()],
], new FirstSuccessfulStrategy());

// Explicit naming (recommended for clarity)
new MultiProvider([
    ['name' => 'LaunchDarkly', 'provider' => $ldProvider],
    ['name' => 'FlagSmith', 'provider' => $fsProvider],
]);

// Auto-generated naming (provider class name is used)
new MultiProvider([
    ['provider' => $ldProvider],  // Named "launchdarkly" (lowercase)
    ['provider' => $fsProvider],  // Named "flagsmith" (lowercase)
    ['provider' => $fsProvider],  // Named "flagsmith_2" (auto-incremented, lowercase)
]);

use OpenFeature\implementation\multiprovider\strategy\FirstMatchStrategy;

$multiProvider = new MultiProvider([
    ['name' => 'Remote', 'provider' => new RemoteProvider()],   // Try remote first
    ['name' => 'Cache', 'provider' => new CacheProvider()],     // Fall back to cache
    ['name' => 'Default', 'provider' => new DefaultProvider()], // Final fallback
], new FirstMatchStrategy());

use OpenFeature\implementation\multiprovider\strategy\FirstSuccessfulStrategy;

$multiProvider = new MultiProvider([
    ['name' => 'Primary', 'provider' => new UnstableProvider()],
    ['name' => 'Secondary', 'provider' => new StableProvider()],
    ['name' => 'Tertiary', 'provider' => new LocalProvider()],
], new FirstSuccessfulStrategy());

use OpenFeature\implementation\multiprovider\strategy\ComparisonStrategy;

// Set up providers
$providerA = new ProviderA();
$multiProvider = new MultiProvider([
    ['provider' => $providerA],
    ['provider' => new ProviderB()],
], new ComparisonStrategy(
    $providerA,  // First argument: "fallback provider" whose value to use when providers don't agree
    function($resolutions) {  // Second argument: callback when values don't match
        error_log('Mismatch detected: ' . json_encode($resolutions));
    }
));

// Example: FirstMatchStrategy with all FLAG_NOT_FOUND
$result = $client->getBooleanDetails('non-existent-flag', false);
// Returns: value=false, reason=ERROR, 
// error="Multi-provider evaluation failed with 3 provider error(s): [ProviderA]: Flag not found; [ProviderB]: Flag not found; [ProviderC]: Flag not found"

// Example: ComparisonStrategy with provider errors
$result = $client->getBooleanDetails('some-flag', false);
// Returns: value=false, reason=ERROR, 
// error="Multi-provider evaluation failed with 2 provider error(s): [ProviderA]: Connection timeout; [ProviderB]: Invalid configuration"

use OpenFeature\OpenFeatureAPI;
use OpenFeature\implementation\multiprovider\MultiProvider;
use OpenFeature\implementation\multiprovider\strategy\FirstMatchStrategy;

// Set up providers
$remoteProvider = new LaunchDarklyProvider($config);
$cacheProvider = new RedisCacheProvider($redis);
$defaultProvider = new InMemoryProvider([
    'feature-enabled' => true,
    'api-timeout' => 30,
]);

// Configure MultiProvider with priority order
$multiProvider = new MultiProvider([
    ['name' => 'LaunchDarkly', 'provider' => $remoteProvider],
    ['name' => 'Redis', 'provider' => $cacheProvider],
    ['name' => 'Defaults', 'provider' => $defaultProvider],
], new FirstMatchStrategy());

// Register with OpenFeature
$api = OpenFeatureAPI::getInstance();
$api->setProvider($multiProvider);

// Use as normal
$client = $api->getClient();
$enabled = $client->getBooleanValue('feature-enabled', false);

// Evaluation flow:
// 1. Try LaunchDarkly → if FLAG_NOT_FOUND, continue
// 2. Try Redis → if FLAG_NOT_FOUND, continue  
// 3. Try Defaults → returns value
// 4. If all fail → returns default with aggregated errors

use OpenFeature\implementation\multiprovider\strategy\BaseEvaluationStrategy;
use OpenFeature\implementation\multiprovider\strategy\ProviderContext;
use OpenFeature\implementation\multiprovider\strategy\StrategyContext;
use OpenFeature\implementation\multiprovider\ProviderResolutionResult;
use OpenFeature\implementation\multiprovider\FinalResult;
use OpenFeature\interfaces\provider\RunMode;

class CustomStrategy extends BaseEvaluationStrategy
{
    // Set to RunMode::EVALUATE_ALL to evaluate all providers at one time
    // or leave as default for sequential evaluation
    public string $runMode = RunMode::SEQUENTIAL;

    /**
     * Called before each provider is evaluated.
     * Return false to skip evaluating this provider.
     */
    public function shouldEvaluateThisProvider(ProviderContext $context): bool
    {
        // Custom logic to determine if this provider should be evaluated
        return true;
    }

    /**
     * Called after a provider is evaluated (sequential mode only).
     * Return false to stop evaluating remaining providers.
     */
    public function shouldEvaluateNextProvider(
        ProviderContext $context,
        ProviderResolutionResult $result
    ): bool {
        // Custom logic to determine if evaluation should continue
        return true;
    }

    /**
     * Called after all providers have been evaluated.
     * Determines the final result to return based on all provider results.
     */
    public function determineFinalResult(
        StrategyContext $context,
        array $resolutions
    ): FinalResult {
        // Custom logic to determine which result to return
        // Can analyze all results and choose one, aggregate them, etc.
        
        // Example: Return first successful result
        foreach ($resolutions as $resolution) {
            if (!$resolution->hasError()) {
                return new FinalResult(
                    $resolution->getDetails(),
                    $resolution->getProviderName(),
                    null
                );
            }
        }
        
        // All failed - return errors
        return new FinalResult(null, null, $this->aggregateErrors($resolutions));
    }
}

// Instead of this (won't execute):
$providerA->addHooks($myHook);

// Do this (will execute):
$client = $api->getClient();
$client->addHooks($myHook);

// add a value to the global context
$api = OpenFeatureAPI::getInstance();
$api->setEvaluationContext(new EvaluationContext('targetingKey', new Attributes(['myGlobalKey' => 'myGlobalValue'])));

// add a value to the client context
$client = $api->getClient();
$client->setEvaluationContext(new EvaluationContext('targetingKey', new Attributes(['myClientKey' => 'myClientValue'])));

// add a value to the invocation context
$context = new EvaluationContext('targetingKey', new Attributes(['myInvocationKey' => 'myInvocationValue']));

$boolValue = $client->getBooleanValue('boolFlag', false, $context);

// add a hook globally, to run on all evaluations
$api = OpenFeatureAPI::getInstance();
$api->addHooks(new ExampleGlobalHook());

// add a hook on this client, to run on all evaluations made by this client
$client = $api->getClient();
$client->addHooks(new ExampleClientHook());

// add a hook for this evaluation only
$value = $client->getBooleanValue("boolFlag", false, $context, new EvaluationOptions([new ExampleInvocationHook()]));

$api = OpenFeatureAPI::getInstance();

$logger = new FancyLogger();

$defaultLoggerClient = $api->getClient('default-logger');

$api->setLogger(new CustomLogger());

$customLoggerClient = $api->getClient('custom-logger');

$overrideLoggerClient = $api->getClient('override-logger');
$overrideLoggerClient->setLogger($logger);

// now let's do some evaluations with these!

$defaultLoggerClient->getBooleanValue('A', false);
// uses default logger in the SDK

$customLoggerClient->getBooleanValue('B', false);
// uses the CustomLogger set in the API before the client was made

$overrideLoggerClient->getBooleanValue('C', false);
// uses the FancyLogger set directly on the client

declare(strict_types=1);

namespace OpenFeature\Example\Providers;

use OpenFeature\implementation\common\Metadata;
use OpenFeature\interfaces\common\Metadata as IMetadata;
use OpenFeature\interfaces\flags\EvaluationContext;
use OpenFeature\interfaces\hooks\Hook;
use OpenFeature\interfaces\provider\Provider;
use OpenFeature\interfaces\provider\ResolutionDetails;

class ExampleProviderImplementation implements Provider
{
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;

        // or, utilize the OpenFeature\interfaces\common\LoggerAwareTrait
    }

    /**
     * @return Hook[]
     */
    public function getHooks(): array
    {
        return $this->hooks; // implement according to the OpenFeature specification
    }

    /**
     * Returns the metadata for the current resource
     */
    public function getMetadata(): IMetadata
    {
        return new Metadata(self::class);
    }

    public function resolveBooleanValue(string $flagKey, bool $defaultValue, ?EvaluationContext $context = null): ResolutionDetails
    {
        // resolve some ResolutionDetails
    }

    public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetails
    {
        // resolve some ResolutionDetails
    }

    public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetails
    {
        // resolve some ResolutionDetails
    }

    public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetails
    {
        // resolve some ResolutionDetails
    }

    /**
     * @inheritdoc
     */
    public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetails
    {
        // resolve some ResolutionDetails
    }
}

declare(strict_types=1);

namespace OpenFeature\Example\Providers;

use OpenFeature\implementation\provider\AbstractProvider;
use OpenFeature\interfaces\flags\EvaluationContext;
use OpenFeature\interfaces\provider\ResolutionDetails as ResolutionDetailsInterface;

class ExampleProviderExtension extends AbstractProvider
{
    protected static string $NAME = self::class;

    public function resolveBooleanValue(string $flagKey, bool $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface
    {
        // resolve some ResolutionDetails
    }

    public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface
    {
        // resolve some ResolutionDetails
    }

    public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface
    {
        // resolve some ResolutionDetails
    }

    public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface
    {
        // resolve some ResolutionDetails
    }

    /**
     * @inheritdoc
     */
    public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface
    {
        // resolve some ResolutionDetails
    }
}

declare(strict_types=1);

namespace OpenFeature\Example\Hooks;

use OpenFeature\interfaces\flags\EvaluationContext;
use OpenFeature\interfaces\flags\FlagValueType;
use OpenFeature\interfaces\hooks\Hook;
use OpenFeature\interfaces\hooks\HookContext;
use OpenFeature\interfaces\hooks\HookHints;
use OpenFeature\interfaces\provider\ResolutionDetails;
use Throwable;


class ExampleStringHookImplementation implements Hook
{
    public function before(HookContext $context, HookHints $hints): ?EvaluationContext
    {
    }

    public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
    {
    }

    public function error(HookContext $context, Throwable $error, HookHints $hints): void
    {
    }

    public function finally(HookContext $context, HookHints $hints): void
    {
    }


    public function supportsFlagValueType(string $flagValueType): bool
    {
        return $flagValueType === FlagValueType::STRING;
    }
}

declare(strict_types=1);

namespace OpenFeature\Example\Hooks;

use OpenFeature\implementation\hooks\StringHook;
use OpenFeature\interfaces\flags\EvaluationContext;
use OpenFeature\interfaces\flags\FlagValueType;
use OpenFeature\interfaces\hooks\HookContext;
use OpenFeature\interfaces\hooks\HookHints;
use OpenFeature\interfaces\provider\ResolutionDetails;
use Throwable;


class ExampleStringHookExtension extends StringHook
{
    public function before(HookContext $context, HookHints $hints): ?EvaluationContext
    {
    }

    public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
    {
    }

    public function error(HookContext $context, Throwable $error, HookHints $hints): void
    {
    }

    public function finally(HookContext $context, HookHints $hints): void
    {
    }
}