Commit 914a826
authored
feat: add evaluateFlags() API for single-call flag evaluation (#131)
* feat: add evaluateFlags() API for single-call flag evaluation
Phase 1 of the Server SDK Feature Flag Evaluations RFC. Mirrors the Node
(posthog-js#3476) and Python (posthog-python#539) implementations.
* `Client::evaluateFlags()` returns a `FeatureFlagEvaluations` snapshot. Reads
on the snapshot do not trigger additional `/flags` requests; access via
`isEnabled` / `getFlag` fires a deduped `$feature_flag_called` event the
first time each key is touched. `getFlagPayload` is silent.
* `capture()` accepts a `flags` snapshot to attach `$feature/<key>` and
`$active_feature_flags` properties without a fresh `/flags` round trip.
* The single-flag dedup is extracted to `Client::captureFlagCalledIfNeeded()`,
shared by the legacy path and the snapshot.
* `flag_keys_to_evaluate` and `geoip_disable` are forwarded on the `/flags`
request body when callers pass `flagKeys` or `disableGeoip`.
* New `feature_flags_log_warnings` option silences filter warnings emitted
from `only()` / `onlyAccessed()`.
Also fixes a pre-existing bug in `SizeLimitedHash::contains/add` that caused
the per-distinct_id `$feature_flag_called` dedup to never match after the
first event. The new snapshot path requires real dedup, and existing tests
only ever made a single call so the bug was invisible until now.
Generated-By: PostHog Code
Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
* chore: silence PSR1.SideEffects warning in evaluate_flags test
The file pairs `require_once 'test/error_log_mock.php'` with class
declarations, matching the pattern in FeatureFlagLocalEvaluationTest.
The existing tests do the same thing; suppressing the rule per-file is
consistent with that precedent.
Generated-By: PostHog Code
Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
* fix: address review feedback on evaluate_flags() PR
Mirrors the fixes applied to posthog-python#539 after review:
* `onlyAccessed()` returns an empty snapshot when nothing has been
accessed instead of warning + falling back to all flags. The fallback
was contradictory with the method's name and surprising for callers
doing `capture(flags: $snapshot->onlyAccessed())` early in a request
before any flag had been read.
* `FeatureFlagEvaluations` tracks `errorsWhileComputingFlags` and
`quotaLimited` from the /flags response and combines them with the
per-flag `flag_missing` error in `$feature_flag_called`, matching the
granularity the single-flag path emits today.
* `capture()` now logs a warning when both `flags` and `send_feature_flags`
are passed; precedence is unchanged (snapshot wins) but the conflict is
no longer silent.
* Tightened the `flagKeys` docstring on `Client::evaluateFlags()` and the
`PostHog::evaluateFlags()` facade so it's clear it scopes the underlying
/flags request, distinct from the in-memory `only([keys])` filter.
Generated-By: PostHog Code
Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
* feat: deprecate legacy single-flag methods and capture send_feature_flags
Phase 2 of the Server SDK Feature Flag Evaluations RFC, shipped alongside
Phase 1 (mirroring posthog-python#539's eda573d).
* `Client::isFeatureEnabled()`, `Client::getFeatureFlag()`, and
`Client::getFeatureFlagPayload()` (along with their `PostHog::*` static
facades) now emit `E_USER_DEPRECATED` pointing at `evaluateFlags()`.
* `capture(['send_feature_flags' => true])` emits the same deprecation when
the legacy block actually runs (the existing precedence — snapshot wins
over `send_feature_flags` — is unchanged).
* `Client::isFeatureEnabled()` now calls `getFeatureFlagResult()` directly
instead of routing through the public `getFeatureFlag()`, so a single
user-level call surfaces exactly one deprecation warning, not two.
* `Client::getFeatureFlagResult()` and `Client::getAllFlags()` are
intentionally NOT deprecated — they expose data (rich single-flag result,
arbitrary key list) that the new snapshot API doesn't yet cover.
`getFeatureFlagPayload()` was already marked `@deprecated` in v4.0.0 with a
message pointing at `getFeatureFlagResult()`. Updated the message to point
at `evaluateFlags()` and added the runtime `trigger_error` so users who pin
warnings to errors (or read PHP error logs) get the heads-up.
Generated-By: PostHog Code
Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d
* fix: address Dustin's review feedback on evaluateFlags() PR
Seven items from the review on #131:
* Skip the /flags request when local definitions cover every flag and they
all evaluate without inconclusive results. The previous code always hit
the server unless `onlyEvaluateLocally` was set, even when local eval
could have answered everything.
* Bring `$feature_flag_called` to parity with the legacy single-flag path:
always emit `locally_evaluated` (true or false, not omitted for remote),
and propagate `$feature_flag_evaluated_at` from the /flags response for
remote records.
* Missing flags now report `$feature_flag_response: null` (not `false`),
matching the legacy single-flag path so consumers can distinguish "flag
exists and is disabled" from "flag not found".
* Defensively handle pre-decoded payloads in the /flags response. Some
middleware deserializes JSON transparently; the snapshot now accepts an
array/object payload as-is instead of feeding it to `json_decode`.
* Deprecate `getFeatureFlagResult()` (and its `PostHog::*` static facade).
Refactored `getFeatureFlagResult` body into a private `doGetFeatureFlagResult`
helper so `isFeatureEnabled()` / `getFeatureFlag()` / `getFeatureFlagPayload()`
can route through it without cascading deprecation warnings.
* Drop the `feature_flags_log_warnings` config option. The only remaining
warning (unknown keys passed to `only([...])`) doesn't warrant a
dedicated knob; if you don't want the warning, fix the typo.
Generated-By: PostHog Code
Task-Id: 1f29305a-ee56-456e-a341-8faa4eb8716d1 parent d70e432 commit 914a826
9 files changed
Lines changed: 1410 additions & 41 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
1 | 16 | | |
2 | 17 | | |
3 | 18 | | |
| |||
0 commit comments