Skip to content

feat: Evaluate flags that depend on other flags - #150

Open
linear-code[bot] wants to merge 3 commits into
mainfrom
linear/sdk-6-enable-flag-dependency-in-the-php-server-side-sdk-3e8e
Open

linear-code[bot] wants to merge 3 commits into
mainfrom
linear/sdk-6-enable-flag-dependency-in-the-php-server-side-sdk-3e8e

Conversation

@linear-code

@linear-code linear-code Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Implements https://linear.app/flagsmith/issue/SDK-6/enable-flag-dependency-in-the-php-server-side-sdk

Ports flag dependency from flagsmith-engine#343. Segment conditions can now read other flags via $.flags.<name>.enabled|value|variant.

  • $.flags is a new LazyFlags (ArrayAccess) bound to the context. It resolves each flag (including its segment overrides) the first time a condition reads it, and memoises segment matches. Any $.flags supplied by the caller is discarded.
  • Cycles are cut rather than recursed into. A segment whose evaluation hit a cycle does not match, and the flags in the cycle report ERROR; code=CIRCULAR_DEPENDENCY.
  • FlagResult now has a variant field: control, the selected variant's key, or null. FeatureValue accepts an optional key. The flag dependency test data requires both.
  • Bumps engine-test-data from v3.7.0 to v3.11.0, the release that adds the flag dependency cases. v3.12 (the STATIC reason) is out of scope; Renovate's deps: update dependency tests/engine/enginetests/enginetestdata to v3.12.1 #138 tracks it.
  • Adds phpbench benchmarks (benchmarks/EngineBench.php). They use the same five contexts as flagsmith-engine's CodSpeed benchmark, the 19 flag dependency cases, and local evaluation through the client (tests/Data/environment.json).

No release is included; the minor version release stays with a human.

Performance

Result: existing flag paths are not at parity. They are 4–5% slower than the baseline, which is 0.13–1.1 µs per call on these small inputs, and peak memory is back to baseline levels. The commit as first pushed (e4a601b) was 7–31% slower and used up to 33 MB peak memory, because each evaluation left a context ↔ LazyFlags reference cycle for the cycle collector. 1649a50 breaks that cycle and skips the lazy flags when there are no segments.

Setup:

  • Baseline: 351aeae (main before this PR).
  • Same machine, PHP 8.5.8 CLI (static-php-cli build, opcache off), phpbench 1.7.0, identical vendor/.
  • Inputs: engine-test-data v3.11.0 and tests/Data/environment.json for every tree.
  • Each run is 1000 revs × 10 iterations; I ran three interleaved rounds per tree.
  • Values below are phpbench mode per iteration, as the median of the three rounds (rstdev ≤ 2.3%).
Subject Baseline 351aeae As pushed e4a601b This PR 1649a50
benchEngine (5 CodSpeed contexts) 22.26 µs, 2.16 MB 23.79 µs, 3.87 MB 23.40 µs (+5.1%), 2.18 MB
benchLocalEvaluationEnvironmentFlags 3.01 µs, 2.11 MB 3.95 µs, 4.46 MB 3.14 µs (+4.3%), 2.11 MB
benchLocalEvaluationIdentityFlags 9.07 µs, 2.19 MB 11.00 µs, 7.40 MB 9.47 µs (+4.4%), 2.21 MB
benchEngineFlagDependency (19 cases) 43.2 µs* 128.3 µs, 33.3 MB 118.2 µs, 2.19 MB

* Not comparable: the baseline can't resolve $.flags, so it does none of the dependency work and returns wrong results for those cases.

To reproduce:

composer install
git worktree add ../baseline 351aeae && cp -a vendor ../baseline/
vendor/bin/phpbench run --bootstrap=../baseline/vendor/autoload.php --tag=baseline --store
vendor/bin/phpbench run --ref=baseline --report=aggregate

The benchmarks are always loaded from this branch; --bootstrap only swaps in the baseline's src/ through its autoloader.

What's left and limitations:

  • The remaining ~0.1–0.4 µs per evaluation is the lazy-flags setup: one shallow context clone, one LazyFlags object and a cycle check per segment. The rest is a few small per-call costs (the new variant field, the overrideWins helper) that each sit below the measurement noise.
  • I also tried passing LazyFlags down to the JSONPath lookup instead of cloning per evaluation. It measured no faster, so I didn't keep it.
  • The fixtures are small (≤ 5 segments and features), so relative overhead on larger environments is unmeasured. The added cost should be constant per evaluation plus a little per segment, but I haven't verified that.
  • Measured on a single shared-tenancy x86_64 VM on PHP 8.5 only, with opcache off. CI's 8.1–8.4 weren't benchmarked.

Segment conditions can now read other flags via `$.flags.<name>`,
resolved lazily with a cycle guard, mirroring flagsmith-engine. Flag
results also carry a `variant` key. Bumps engine-test-data to v3.11.0.

Generated with [Linear](https://linear.app/flagsmith/agent-session/d9c8ddc7-fa40-4842-80da-7e01be1b4f77)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@linear-code
linear-code Bot requested a review from a team as a code owner October 21, 2026 17:14
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: a1f73133-beac-4b71-a8ad-eb66189538a4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

emyller and others added 2 commits October 21, 2026 18:25
Covers the flagsmith-engine CodSpeed contexts, the flag dependency
cases, and local evaluation through the client.

Generated with [Linear](https://linear.app/flagsmith/agent-session/d9c8ddc7-fa40-4842-80da-7e01be1b4f77)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
Skip the lazy flags when there are no segments, and break the
context/flags reference cycle so each evaluation is freed by reference
counting rather than left to the cycle collector.

Generated with [Linear](https://linear.app/flagsmith/agent-session/d9c8ddc7-fa40-4842-80da-7e01be1b4f77)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant