Powering Up PHP Feature Flags with OpenFeature

See just how easy it is to break free from vendor lock-in with OpenFeature in our latest blog post, where we detail the straightforward process of tweaking our PHP example app to embrace the OpenFeature standard.

Powering Up PHP Feature Flags with OpenFeature

Diving into the world of feature flags can sometimes seem daunting, especially when you're new to a feature flagging platform. Recognizing this challenge, in 2024 DevCycle embarked on a mission to develop some intuitive example applications—now available in the DevCycle Labs GitHub organization—designed to simplify the feature flagging process for newcomers.

DevCycle Labs
DevCycle Examples, Documentation and other helpful tidbits! - DevCycle Labs

Check out the DevCycle Labs Organization where you can find all of our example projects.

Offering more than a dozen different flavours, these example applications now allow users to experiment with various features available through the DevCycle platform in a much more intuitive and user-friendly way.

0:00
/0:08

Demo of the PHP Example application described in this blog post.

While these new example applications are essential in welcoming new users to our platform, our team's dedication to the feature flagging ecosystem reaches well beyond merely attracting newcomers to DevCycle. We strive to foster the most effective use of feature flags. And so, in the rapidly growing world of feature management, this commitment translates into integrating OpenFeature.

Future-proofing Feature Flags with OpenFeature
Have you noticed the buzz around feature flags lately? It’s not just you—they’ve truly exploded in popularity. In just the past five years, the average search traffic for feature flags on Google has tripled! With this surge in popularity, the ecosystem for feature flags has expanded massively. Dozens of

Learn more about the growth of feature flagging and the rise of OpenFeature in this post.

Why focus on PHP for this OpenFeature conversion?

As a huge fan of PHP, thanks in part to its straightforward syntax and status as an extremely popular language for web development, I recently began the task of converting our example applications to implement the OpenFeature standard.

While PHP's syntax is distinct, the foundational work by our team on these example applications and the OpenFeature Providers ensures that much of the conversion process would be analogous across different languages and frameworks. This made PHP a prime candidate for a case study to explore the necessary adjustments for implementing OpenFeature effectively.

GitHub - DevCycleHQ-Labs/example-php: An example app built using the DevCycle PHP SDK
An example app built using the DevCycle PHP SDK. Contribute to DevCycleHQ-Labs/example-php development by creating an account on GitHub.

Check out the original DevCycle Example Application written in PHP.

In our original PHP example application, we were working with four crucial and interconnected files:

  1. devcycle.php - The starting point where we establish our connection to the DevCycle platform and instantiate the DevCycle client.
  2. index.php - Where we define the devcycle_client and user_data variables used in our feature flag evaluation process.
  3. togglebot.php & description.php - Where the magic happens:
    • In togglebot.php, we evaluate a string and a boolean variable to animate the Togglebot image and its message.
      • Here we also implement the allFeatures hook, a native functionality of DevCycle, to showcase the "Serving Variation" block below the animated Togglebot.
    • In description.php, a string variable controls the text displayed below the image, providing context to the tutorial's progression

Moving from Vendor-locked to OpenFeature:

Here's a snippet from devcycle.php in our original PHP example application to get us started:

use DevCycle\Api\DevCycleClient;
use DevCycle\Model\DevCycleOptions;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->load();

$options = new DevCycleOptions();

$devcycle_client = new DevCycleClient(
    sdkKey: $_ENV["DEVCYCLE_SERVER_SDK_KEY"],
    dvcOptions: $options
);

To align with the OpenFeature standard, we had to make a few notable changes. First we needed to enable the OpenFeature API functionality in the DevCycle SDK through DevCycleOptions object, and to instantiate the OpenFeature API itself. From there, we needed to set the Provider to DevCycle's OpenFeatureProvider before finally instantiating the OpenFeature client for use in flag evaluations in our application.

use DevCycle\Api\DevCycleClient;
use DevCycle\Model\DevCycleOptions;
use OpenFeature\OpenFeatureAPI;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->load();

$options = new DevCycleOptions(true); // Enabling OpenAPI features

$devcycle_client = new DevCycleClient(
    sdkKey: $_ENV["DEVCYCLE_SERVER_SDK_KEY"], 
    dvcOptions: $options 
);

$api = OpenFeatureAPI::getInstance();

$api->setProvider($devcycle_client->getOpenFeatureProvider());

$openfeature_client = $api->getClient();

Moving onto index.php, our original example laid the groundwork for feature flag evaluations by creating a user-specific data object for use by the DevCycle SDK in the targeting process.

use DevCycle\Model\DevCycleUser;

$user_data = new DevCycleUser(array(
"user_id"=>"my-user"
));

The shift towards adopting OpenFeature, however, required a rethink in how we structure the data for use in feature flag evaluations. Rather than solely containing user-specific data for targeting, OpenFeature's EvaluationContext object is designed to be data-agnostic, accommodating various types of information used in the flag evaluation process for targeting. With this in mind, we needed to turn to OpenFeature's Attributes object in order to utilize our existing structure of user data, and feed it a digestible way to the OpenFeature API.

use OpenFeature\implementation\flags\EvaluationContext;
use OpenFeature\implementation\flags\Attributes;
use DevCycle\Model\DevCycleUser;

$user_attributes = new Attributes(array("user_id" => "my-user"));

$openfeature_context = new EvaluationContext(attributes: $user_attributes);

$devcycle_user_data = DevCycleUser::FromEvaluationContext($openfeature_context);

With much of the "heavy lifting" now complete in those other files, there were only a few minor changes remaining in togglebot.php and description.php to get OpenFeature functional. These primarily involved differences in the hooks used to retrieve the variable value in the DevCycle client versus the OpenFeature client.

To understand what I mean here, lets first look to the $step variable in description.php where our original example application relied on the variableValue hook in DevCycle client to retrieve feature flag values:

$step = $devcycle_client->variableValue($user_data, "example-text", "default");

With the OpenFeature client, this hook becomes much more explicit, using getStringValue for string-based feature flags.

$step = $openfeature_client->getStringValue("example-text", "default", $openfeature_context);

You may also notice another important change in this implementation around the ordering of parameters in these functions. Whereas the DevCycle hooks were ordered (user_data, variation_name, default_value) in the OpenFeature context we input them as (variation_name, default_value, user_data) .

We can also see this change in action in the $speed variable in togglebot.php. Here we again shifted from the variableValue hook to getStringValue and also introduced the (again more explicit) getBooleanValue hook for $wink:

// Original DevCycle Example Application
$speed = $devcycle_client->variableValue($user_data, "togglebot-speed", "off");
$wink = $devcycle_client->variableValue($user_data, "togglebot-wink", false);

// Revision for OpenFeature Provider Implementation
$speed = $openfeature_client->getStringValue("togglebot-speed", "off", $openfeature_context);
$wink = $openfeature_client->getBooleanValue("togglebot-wink", false, $openfeature_context);

Okay, but why maintain both clients?

You might wonder why we chose to keep both devcycle_client and openfeature_client in our updated example. The answer lies in togglebot.php.

While OpenFeature provides a versatile framework for feature flagging, we encounter moments where DevCycle-specific functionalities, like events for A/B testing evaluation, are indispensable for full compatibility.

In our situation, the need for compatibility emerged around $features. This variable in index.php necessitated the allFeatures hook to parse all features available for a user on the DevCycle platform, identify the feature with the hello-togglebot key, and display the name of the variation being served.

$features = $devcycle_client->allFeatures($devcycle_user_data);

$variation_name = $features["hello-togglebot"]
    ? $features["hello-togglebot"]["variationName"]
    : "Default";

Unfortunately, despite OpenFeature providing a powerful API, the functionality needed for this specific implementation is not yet available and as a result, we needed to maintain both clients for use in this demo application.

Are there any "gotchas" with this example?

Something to note in this setup is the integration within the standard PHP SDK for DevCycle, which already includes the OpenFeature SDK and the OpenFeature PHP Provider. This integration simplifies the process, eliminating the need for separate installations of the OpenFeature components. That said, the requirement for additional installations might vary based on the specific vendor you're utilizing.

That sounds straightforward, what's next?

As you can see, by making a few small adjustments to your current codebase (and with some assistance from your existing vendor in the form of an OpenFeature Provider) you can begin to future-proof your feature flag implementations. This approach not only enhances your system's adaptability but also ensures a smoother transition to newer technologies and standards in the future.

Where can I access your code?

Visit the DevCycle Labs GitHub organization to explore the repository for the new PHP OpenFeature example application and see these modifications applied in this tutorial in practice:

GitHub - DevCycleHQ-Labs/example-php-openfeature: An example app built using the OpenFeature PHP SDK
An example app built using the OpenFeature PHP SDK - DevCycleHQ-Labs/example-php-openfeature

Check out the code for the updated PHP example application which implements OpenFeature