Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/feature-flag-evaluations-default-value.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"posthog-php": minor
---

Add an optional `$defaultValue` parameter to `FeatureFlagEvaluations::isEnabled()`. Previously, an unknown/unresolved flag always collapsed to `false` with no way for a caller to distinguish "flag is off" from "flag has no value" β€” the spec requires the SDK to return a caller-supplied default in that case. `isEnabled($key, defaultValue: true)` now returns `true` when the flag has no resolvable value; a flag with a real value, including `false`, always wins over the default. Existing callers who don't pass it see identical behavior.
10 changes: 10 additions & 0 deletions api/public-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -2695,6 +2695,16 @@
"default": null,
"defaultConstant": null,
"hasDefault": false
},
{
"name": "defaultValue",
"type": "bool",
"byReference": false,
"variadic": false,
"optional": true,
"default": false,
"defaultConstant": null,
"hasDefault": true
}
]
},
Expand Down
8 changes: 5 additions & 3 deletions lib/FeatureFlagEvaluations.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@ public function getKeys(): array
}

/**
* Whether the flag is enabled for the snapshot's distinct id. Returns false for unknown keys.
* Whether the flag is enabled for the snapshot's distinct id. Returns $defaultValue for
* unknown keys; a flag with a real value (including false) always takes precedence.
*
* @param string $key Feature flag key.
* @param bool $defaultValue Value to return when the flag has no resolvable value.
* @return bool
*/
public function isEnabled(string $key): bool
public function isEnabled(string $key, bool $defaultValue = false): bool
{
$record = $this->flags[$key] ?? null;
$this->recordAccess($key, $record);

return $record?->enabled ?? false;
return $record?->enabled ?? $defaultValue;
}

/**
Expand Down
28 changes: 28 additions & 0 deletions test/FeatureFlagEvaluationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,34 @@ public function testUnknownKeyAccessRecordsFlagMissingError(): void
$this->assertSame('flag_missing', $properties['$feature_flag_error']);
}

public function testIsEnabledReturnsCallerSuppliedDefaultForUnknownKey(): void
{
$host = new FakeFlagEvaluationsHost();
$snapshot = new FeatureFlagEvaluations(
'user-1',
[],
[],
$host
);

$this->assertTrue($snapshot->isEnabled('does-not-exist', true));
$this->assertFalse($snapshot->isEnabled('does-not-exist'));
$this->assertFalse($snapshot->isEnabled('does-not-exist', false));
}

public function testIsEnabledDefaultDoesNotOverrideARealFalseValue(): void
{
$host = new FakeFlagEvaluationsHost();
$snapshot = new FeatureFlagEvaluations(
'user-1',
['flag-a' => $this->makeRecord('flag-a', false)],
[],
$host
);

$this->assertFalse($snapshot->isEnabled('flag-a', true));
}

public function testOnlyWarnsOnUnknownKeys(): void
{
$host = new FakeFlagEvaluationsHost();
Expand Down
Loading