From 84f7ed01fdb924179c42322adb4be33342891dbe Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 13:59:02 +0000 Subject: [PATCH 1/8] chore: bump phpstan version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4c79d16..3eb3706 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "~1.10.0", + "phpstan/phpstan": "^1.11.0", "phpstan/phpstan-mockery": "^1.0", "phpstan/phpstan-phpunit": "^1.1", "psalm/plugin-mockery": "^1.0.0", From 10283e62fa410d2b94ab198900606e3eb9d2de0c Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 13:59:58 +0000 Subject: [PATCH 2/8] chore: do not create composer.lock --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 3eb3706..c5c5157 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,7 @@ "phpstan/extension-installer": true, "ramsey/composer-repl": true }, + "lock": false, "sort-packages": true }, "extra": { From 34183e5bab358ea093ddf8e7ea48dfb2d280e7f0 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:03:23 +0000 Subject: [PATCH 3/8] docs: fixed array casing in phpdoc --- src/OpenFeatureAPI.php | 2 +- src/implementation/events/EventMetadata.php | 6 +++--- src/implementation/events/HandlerAdderTrait.php | 2 +- src/implementation/flags/Attributes.php | 6 +++--- src/implementation/flags/FlagMetadata.php | 6 +++--- src/implementation/flags/MutableAttributes.php | 4 ++-- src/implementation/hooks/HookHints.php | 2 +- src/interfaces/events/EventDetails.php | 2 +- src/interfaces/events/EventMetadata.php | 2 +- src/interfaces/flags/Attributes.php | 4 ++-- src/interfaces/flags/FlagMetadata.php | 4 ++-- src/interfaces/hooks/HooksAwareTrait.php | 2 +- tests/unit/BaseHooksTest.php | 10 +++++----- tests/unit/StringHelperTest.php | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/OpenFeatureAPI.php b/src/OpenFeatureAPI.php index 3e761f5..66eeb78 100644 --- a/src/OpenFeatureAPI.php +++ b/src/OpenFeatureAPI.php @@ -42,7 +42,7 @@ final class OpenFeatureAPI implements API, LoggerAwareInterface /** @var (Client & ProviderAware) | null $defaultClient */ private $defaultClient; - /** @var Array $clientMap */ + /** @var array $clientMap */ private array $clientMap = []; /** @var Hook[] $hooks */ diff --git a/src/implementation/events/EventMetadata.php b/src/implementation/events/EventMetadata.php index 80bde7a..a8ae266 100644 --- a/src/implementation/events/EventMetadata.php +++ b/src/implementation/events/EventMetadata.php @@ -13,7 +13,7 @@ class EventMetadata implements EventMetadataInterface { /** - * @param Array $eventMetadataMap + * @param array $eventMetadataMap */ public function __construct(protected array $eventMetadataMap = []) { @@ -27,7 +27,7 @@ public function has(string $key): bool /** * Return key-type pairs of the EventMetadata * - * @return Array + * @return array */ public function keys(): array { @@ -44,7 +44,7 @@ public function get(string $key): bool | string | int | float | null } /** - * @return Array + * @return array */ public function toArray(): array { diff --git a/src/implementation/events/HandlerAdderTrait.php b/src/implementation/events/HandlerAdderTrait.php index 0882983..5916c01 100644 --- a/src/implementation/events/HandlerAdderTrait.php +++ b/src/implementation/events/HandlerAdderTrait.php @@ -7,7 +7,7 @@ trait HandlerAdderTrait { /** - * @var Array $handlers + * @var array $handlers */ private array $handlers = []; } diff --git a/src/implementation/flags/Attributes.php b/src/implementation/flags/Attributes.php index 34837f3..25120a5 100644 --- a/src/implementation/flags/Attributes.php +++ b/src/implementation/flags/Attributes.php @@ -11,7 +11,7 @@ class Attributes implements AttributesInterface { /** - * @param Array $attributesMap + * @param array $attributesMap */ public function __construct(protected array $attributesMap = []) { @@ -20,7 +20,7 @@ public function __construct(protected array $attributesMap = []) /** * Return key-type pairs of the attributes * - * @return Array + * @return array */ public function keys(): array { @@ -36,7 +36,7 @@ public function get(string $key): bool | string | int | float | DateTime | array } /** - * @return Array + * @return array */ public function toArray(): array { diff --git a/src/implementation/flags/FlagMetadata.php b/src/implementation/flags/FlagMetadata.php index 01a26f3..ce287a7 100644 --- a/src/implementation/flags/FlagMetadata.php +++ b/src/implementation/flags/FlagMetadata.php @@ -10,7 +10,7 @@ class FlagMetadata implements FlagMetadataInterface { /** - * @param Array $metadata + * @param array $metadata */ public function __construct(protected array $metadata = []) { @@ -19,7 +19,7 @@ public function __construct(protected array $metadata = []) /** * Return key-type pairs of the attributes * - * @return Array + * @return array */ public function keys(): array { @@ -32,7 +32,7 @@ public function get(string $key): bool | string | int | float | null } /** - * @return Array + * @return array */ public function toArray(): array { diff --git a/src/implementation/flags/MutableAttributes.php b/src/implementation/flags/MutableAttributes.php index 662ce7c..7ffccea 100644 --- a/src/implementation/flags/MutableAttributes.php +++ b/src/implementation/flags/MutableAttributes.php @@ -17,9 +17,9 @@ public static function from(AttributesInterface $attributes): MutableAttributes $attributeMap = array_reduce( $attributes->keys(), /** - * @param Array $map + * @param array $map * - * @return Array + * @return array */ function (array $map, string $key) use ($attributes) { $map[$key] = $attributes->get($key); diff --git a/src/implementation/hooks/HookHints.php b/src/implementation/hooks/HookHints.php index a237777..958656d 100644 --- a/src/implementation/hooks/HookHints.php +++ b/src/implementation/hooks/HookHints.php @@ -13,7 +13,7 @@ class HookHints implements HookHintsInterface { /** - * @param Array $hints + * @param array $hints */ public function __construct(private readonly array $hints = []) { diff --git a/src/interfaces/events/EventDetails.php b/src/interfaces/events/EventDetails.php index 8922636..e1dfb68 100644 --- a/src/interfaces/events/EventDetails.php +++ b/src/interfaces/events/EventDetails.php @@ -9,7 +9,7 @@ interface EventDetails public function getClientName(): string; /** - * @return Array + * @return array */ public function getChangedFlags(): array; diff --git a/src/interfaces/events/EventMetadata.php b/src/interfaces/events/EventMetadata.php index 25cff73..908143a 100644 --- a/src/interfaces/events/EventMetadata.php +++ b/src/interfaces/events/EventMetadata.php @@ -16,7 +16,7 @@ public function get(string $key): bool | string | int | float | null; public function keys(): array; /** - * @return Array + * @return array */ public function toArray(): array; } diff --git a/src/interfaces/flags/Attributes.php b/src/interfaces/flags/Attributes.php index 1adb975..e75747d 100644 --- a/src/interfaces/flags/Attributes.php +++ b/src/interfaces/flags/Attributes.php @@ -11,7 +11,7 @@ interface Attributes /** * Return key-type pairs of the attributes * - * @return Array + * @return array */ public function keys(): array; @@ -21,7 +21,7 @@ public function keys(): array; public function get(string $key): bool | string | int | float | DateTime | array | null; /** - * @return Array + * @return array */ public function toArray(): array; } diff --git a/src/interfaces/flags/FlagMetadata.php b/src/interfaces/flags/FlagMetadata.php index 554180d..5aac72e 100644 --- a/src/interfaces/flags/FlagMetadata.php +++ b/src/interfaces/flags/FlagMetadata.php @@ -13,14 +13,14 @@ interface FlagMetadata /** * Return key-type pairs of the attributes * - * @return Array + * @return array */ public function keys(): array; public function get(string $key): bool | string | int | float | null; /** - * @return Array + * @return array */ public function toArray(): array; } diff --git a/src/interfaces/hooks/HooksAwareTrait.php b/src/interfaces/hooks/HooksAwareTrait.php index 566de73..e1e978e 100644 --- a/src/interfaces/hooks/HooksAwareTrait.php +++ b/src/interfaces/hooks/HooksAwareTrait.php @@ -6,7 +6,7 @@ trait HooksAwareTrait { - /** @var Array $hooks */ + /** @var array $hooks */ private array $hooks = []; /** diff --git a/tests/unit/BaseHooksTest.php b/tests/unit/BaseHooksTest.php index ac76629..9fe3d6e 100644 --- a/tests/unit/BaseHooksTest.php +++ b/tests/unit/BaseHooksTest.php @@ -50,7 +50,7 @@ public function finally(HookContext $context, HookHints $hints): void } /** - * @return Array> + * @return array> */ public function dataBooleanHook(): array { @@ -94,7 +94,7 @@ public function finally(HookContext $context, HookHints $hints): void } /** - * @return Array> + * @return array> */ public function dataFloatHook(): array { @@ -138,7 +138,7 @@ public function finally(HookContext $context, HookHints $hints): void } /** - * @return Array> + * @return array> */ public function dataIntegerHook(): array { @@ -182,7 +182,7 @@ public function finally(HookContext $context, HookHints $hints): void } /** - * @return Array> + * @return array> */ public function dataObjectHook(): array { @@ -226,7 +226,7 @@ public function finally(HookContext $context, HookHints $hints): void } /** - * @return Array> + * @return array> */ public function dataStringHook(): array { diff --git a/tests/unit/StringHelperTest.php b/tests/unit/StringHelperTest.php index 52e4954..86509cf 100644 --- a/tests/unit/StringHelperTest.php +++ b/tests/unit/StringHelperTest.php @@ -20,7 +20,7 @@ public function testCapitalize(string $input, string $expectedValue): void } /** - * @return Array> + * @return array> */ public function capitalizeData(): array { @@ -46,7 +46,7 @@ public function testDecapitalize(string $input, string $expectedValue): void } /** - * @return Array> + * @return array> */ public function decapitalizeData(): array { From 6d8c2848fb5ab3c4ef05783bf324315eb7da53a4 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:05:14 +0000 Subject: [PATCH 4/8] chore: MutableAttributes declare static callback to array_reduce --- src/implementation/flags/MutableAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/implementation/flags/MutableAttributes.php b/src/implementation/flags/MutableAttributes.php index 7ffccea..73b152b 100644 --- a/src/implementation/flags/MutableAttributes.php +++ b/src/implementation/flags/MutableAttributes.php @@ -21,7 +21,7 @@ public static function from(AttributesInterface $attributes): MutableAttributes * * @return array */ - function (array $map, string $key) use ($attributes) { + static function (array $map, string $key) use ($attributes) { $map[$key] = $attributes->get($key); return $map; From 259c66ad5f594a4da8e1475e0b76f77337b6f613 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:05:58 +0000 Subject: [PATCH 5/8] chore: simplify StringHelper capitalization methods --- src/implementation/common/StringHelper.php | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/implementation/common/StringHelper.php b/src/implementation/common/StringHelper.php index 447a72d..628e4cf 100644 --- a/src/implementation/common/StringHelper.php +++ b/src/implementation/common/StringHelper.php @@ -4,28 +4,18 @@ namespace OpenFeature\implementation\common; -use function strlen; -use function strtolower; -use function strtoupper; -use function substr; +use function lcfirst; +use function ucfirst; class StringHelper { public static function capitalize(string $input): string { - return match (strlen($input)) { - 0 => '', - 1 => strtoupper($input), - default => strtoupper(substr($input, 0, 1)) . substr($input, 1), - }; + return ucfirst($input); } public static function decapitalize(string $input): string { - return match (strlen($input)) { - 0 => '', - 1 => strtolower($input), - default => strtolower(substr($input, 0, 1)) . substr($input, 1), - }; + return lcfirst($input); } } From f8a15f4ef170f3a8b02a4b11be306387803867d3 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:06:29 +0000 Subject: [PATCH 6/8] chore: simplify ArrayHelper getStringKeys method --- src/implementation/common/ArrayHelper.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/implementation/common/ArrayHelper.php b/src/implementation/common/ArrayHelper.php index 4521cfa..6145348 100644 --- a/src/implementation/common/ArrayHelper.php +++ b/src/implementation/common/ArrayHelper.php @@ -4,9 +4,8 @@ namespace OpenFeature\implementation\common; +use function array_is_list; use function array_keys; -use function is_int; -use function sizeof; class ArrayHelper { @@ -19,17 +18,8 @@ class ArrayHelper * * @return array */ - public static function getStringKeys(array $array) + public static function getStringKeys(array $array): array { - $keys = array_keys($array); - - if (sizeof($keys) === 0 || is_int($keys[0])) { - return []; - } - - /** @var array $stringKeys */ - $stringKeys = $keys; - - return $stringKeys; + return array_is_list($array) ? [] : array_keys($array); } } From 6c22459ee5601d70ae630de004fc11c4da552d70 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:08:08 +0000 Subject: [PATCH 7/8] refactor: added FlagValueType::tryFromResolutionDetails() method --- src/interfaces/flags/FlagValueType.php | 52 ++++++++++++++++---------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/interfaces/flags/FlagValueType.php b/src/interfaces/flags/FlagValueType.php index 9108d77..1eea6ca 100644 --- a/src/interfaces/flags/FlagValueType.php +++ b/src/interfaces/flags/FlagValueType.php @@ -4,6 +4,14 @@ namespace OpenFeature\interfaces\flags; +use OpenFeature\interfaces\provider\ResolutionDetails; + +use function is_array; +use function is_bool; +use function is_float; +use function is_int; +use function is_string; + enum FlagValueType: string { case String = 'STRING'; @@ -12,24 +20,28 @@ enum FlagValueType: string case Object = 'OBJECT'; case Boolean = 'BOOLEAN'; - /** - * @deprecated prefer enum value over const - */ - public const STRING = 'STRING'; - /** - * @deprecated prefer enum value over const - */ - public const INTEGER = 'INTEGER'; - /** - * @deprecated prefer enum value over const - */ - public const FLOAT = 'FLOAT'; - /** - * @deprecated prefer enum value over const - */ - public const OBJECT = 'OBJECT'; - /** - * @deprecated prefer enum value over const - */ - public const BOOLEAN = 'BOOLEAN'; + public static function tryFromResolutionDetails(ResolutionDetails $resolutionDetails): ?self + { + $value = $resolutionDetails->getValue(); + + return match (true) { + is_bool($value) => self::Boolean, + is_float($value) => self::Float, + is_int($value) => self::Integer, + is_string($value) => self::String, + is_array($value) => self::Object, + default => null, + }; + } + + /** @deprecated prefer enum value over const */ + public const STRING = self::String; + /** @deprecated prefer enum value over const */ + public const INTEGER = self::Integer; + /** @deprecated prefer enum value over const */ + public const FLOAT = self::Float; + /** @deprecated prefer enum value over const */ + public const OBJECT = self::Object; + /** @deprecated prefer enum value over const */ + public const BOOLEAN = self::Boolean; } From 6569b19510773342c199c97aa7bf68f9bde26ad6 Mon Sep 17 00:00:00 2001 From: Chris Lightfoot-Wild Date: Sat, 22 Mar 2025 14:10:03 +0000 Subject: [PATCH 8/8] refactor: replace ValueTypeValidator usage with FlagValueType comparison to ResolutionDetails --- src/OpenFeatureClient.php | 38 ++------ .../common/ValueTypeValidator.php | 87 ------------------- 2 files changed, 9 insertions(+), 116 deletions(-) delete mode 100644 src/implementation/common/ValueTypeValidator.php diff --git a/src/OpenFeatureClient.php b/src/OpenFeatureClient.php index 28aae6c..f90f0c2 100644 --- a/src/OpenFeatureClient.php +++ b/src/OpenFeatureClient.php @@ -5,7 +5,6 @@ namespace OpenFeature; use OpenFeature\implementation\common\Metadata; -use OpenFeature\implementation\common\ValueTypeValidator; use OpenFeature\implementation\errors\InvalidResolutionValueError; use OpenFeature\implementation\flags\EvaluationContext; use OpenFeature\implementation\flags\EvaluationDetailsBuilder; @@ -346,7 +345,7 @@ private function evaluateFlag( $mergedContext, ); - if (!$resolutionDetails->getError() && !ValueTypeValidator::is($flagValueType, $resolutionDetails->getValue())) { + if (!$resolutionDetails->getError() && $flagValueType !== FlagValueType::tryFromResolutionDetails($resolutionDetails)) { throw new InvalidResolutionValueError($flagValueType->value); } @@ -388,33 +387,14 @@ private function createProviderEvaluation( Provider $provider, EvaluationContextInterface $context, ): ResolutionDetails { - switch ($type->value) { - case FlagValueType::Boolean->value: - /** @var bool $defaultValue */; - $defaultValue = $defaultValue; - - return $provider->resolveBooleanValue($key, $defaultValue, $context); - case FlagValueType::String->value: - /** @var string $defaultValue */; - $defaultValue = $defaultValue; - - return $provider->resolveStringValue($key, $defaultValue, $context); - case FlagValueType::Integer->value: - /** @var int $defaultValue */; - $defaultValue = $defaultValue; - - return $provider->resolveIntegerValue($key, $defaultValue, $context); - case FlagValueType::Float->value: - /** @var float $defaultValue */; - $defaultValue = $defaultValue; - - return $provider->resolveFloatValue($key, $defaultValue, $context); - case FlagValueType::Object->value: - /** @var mixed[] $defaultValue */; - $defaultValue = $defaultValue; - - return $provider->resolveObjectValue($key, $defaultValue, $context); - } + /** @psalm-suppress InvalidArgument,PossiblyInvalidArgument,PossiblyInvalidCast */ + return match ($type) { + FlagValueType::Boolean => $provider->resolveBooleanValue($key, $defaultValue, $context), // @phpstan-ignore argument.type + FlagValueType::String => $provider->resolveStringValue($key, $defaultValue, $context), // @phpstan-ignore argument.type + FlagValueType::Integer => $provider->resolveIntegerValue($key, $defaultValue, $context), // @phpstan-ignore argument.type + FlagValueType::Float => $provider->resolveFloatValue($key, $defaultValue, $context), // @phpstan-ignore argument.type + FlagValueType::Object => $provider->resolveObjectValue($key, $defaultValue, $context), // @phpstan-ignore argument.type + }; } private function determineProvider(): Provider diff --git a/src/implementation/common/ValueTypeValidator.php b/src/implementation/common/ValueTypeValidator.php deleted file mode 100644 index 3fd12e7..0000000 --- a/src/implementation/common/ValueTypeValidator.php +++ /dev/null @@ -1,87 +0,0 @@ - self::isBoolean($value), - FlagValueType::Float => self::isFloat($value), - FlagValueType::Integer => self::isInteger($value), - FlagValueType::String => self::isString($value), - FlagValueType::Object => self::isStructure($value) || self::isArray($value), - }; - } -}