feat(ffe): add runtime-backed PHP feature flag evaluation#3906
feat(ffe): add runtime-backed PHP feature flag evaluation#3906leoromanovsky wants to merge 12 commits into
Conversation
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 782f622 | Docs | Datadog PR Page | Give us feedback! |
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 555e9a0 | Docs | Datadog PR Page | Give us feedback! |
Benchmarks [ tracer ]Benchmark execution time: 2026-05-22 20:45:03 Comparing candidate commit 555e9a0 in PR branch Found 0 performance improvements and 4 performance regressions! Performance is the same for 190 metrics, 0 unstable metrics. scenario:MessagePackSerializationBench/benchMessagePackSerialization
scenario:PDOBench/benchPDOOverhead
scenario:PDOBench/benchPDOOverheadWithDBM
scenario:PHPRedisBench/benchRedisOverhead
|
…stone-1-runtime-evaluation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e55ebb976b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| EvaluationError::FlagDisabled => (ERROR_NONE, REASON_DISABLED), | ||
| EvaluationError::DefaultAllocationNull => (ERROR_NONE, REASON_DEFAULT), |
There was a problem hiding this comment.
Preserve disabled/default results instead of null coercion
For a disabled flag this returns error_code = 0 with value_json = "null", but ResultMapper::map() treats any zero-error result as a real variation value and then fails to coerce null to the requested type, converting disabled flags into TYPE_MISMATCH errors instead of returning the caller default with EvaluationReason::DISABLED. The same path affects DefaultAllocationNull; handle these no-assignment cases before decoding or surface an error/default signal that the PHP mapper can distinguish.
Useful? React with 👍 / 👎.
Motivation
PHP FFE needs a mergeable Milestone 1 artifact that proves real evaluations through Remote Config and the
libdatadogRust evaluator before adding exposure delivery, exposure caching, or flag-evaluation metrics.This is the evaluation-only product slice: PHP 7 gets a Datadog API, PHP 8 can use the optional OpenFeature bridge, and both read from the live Remote Config-backed native runtime. The remaining product work is intentionally left for later milestones.
Shared planning doc: https://docs.google.com/document/d/1NvMfTpZWLBlFmEFNjdnlMyeVpy5l7KD8qujGFco6w2w/edit?tab=t.0
Changes
libdatadogFFE evaluator path and keeps PHP user-facing APIs as thin adapters over the native runtime.DDTrace\FeatureFlagsevaluation through live Remote Config.DDTrace\OpenFeatureoptional bridge without addingopen-feature/sdkas a root dependency.DataDog/ffe-system-test-datasubmodule and a native-runtime PHPT loop overufc-config.jsonandevaluation-cases/*.json.Not included
Decisions
DDTrace\Testing\ffe_load_configexists only for local/canonical fixture tests.USE_ZEND_ALLOC=0) because it is a semantic fixture sweep over the Rust evaluator, not a memory-leak test.Local validation
php vendor/bin/phpunit --config phpunit.xml tests/api/Unit/FeatureFlags tests/OpenFeature/DataDogProviderTest.php: 29 tests / 87 assertions.make test_featureflags: 8 tests / 29 assertions.MAX_TEST_PARALLELISM=1 TESTS=tests/ext/ffe/native_bridge_evaluate.phpt make test_c: 1/1 passed.MAX_TEST_PARALLELISM=1 TESTS=tests/ext/ffe/system_test_data_evaluate.phpt make test_c: 1/1 passed.make test_internal_api_randomized: passed.Dogfooding validation
See DataDog/ffe-dogfooding#68.
The local compose stack demonstrated PHP 7 and PHP 8/OpenFeature receiving live Remote Config updates and returning non-default values matching GA SDKs, including JSON/object variants.
System-tests validation
See DataDog/system-tests#7003.
Built a local PHP 8.2 arm64 artifact with:
Validated against PHP parametric system-tests:
test-json-config-flag.json: 1/1 passed.test-case-of-7-empty-targeting-key.json: 1/1 passed.Test_Feature_Flag_Dynamic_Evaluation: 25/25 passed.Test_Parametric_FFE_Start: 1/1 passed.