open-feature / sdk
OpenFeature SDK 的 PHP 实现
Requires
- php: ^8
- myclabs/php-enum: ^1.8
- psr/log: ^2.0 || ^3.0
Requires (Dev)
- behat/behat: ^3.11
- captainhook/captainhook: ^5.10
- captainhook/plugin-composer: ^5.3
- ergebnis/composer-normalize: ^2.25
- hamcrest/hamcrest-php: ^2.0
- mdwheele/zalgo: ^0.3.1
- mockery/mockery: ^1.5
- 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-mockery: ^1.0
- phpstan/phpstan-phpunit: ^1.1
- psalm/plugin-mockery: ^1.0.0
- psalm/plugin-phpunit: ^0.19.0
- ramsey/coding-standard: ^2.0.3
- ramsey/composer-repl: ^1.4
- ramsey/conventional-commits: ^1.3
- roave/security-advisories: dev-latest
- spatie/phpunit-snapshot-assertions: ^4.2
- vimeo/psalm: ~5.25.0
- dev-main
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.4.0
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.0
- 0.1.1
- 0.1.0
- 0.0.10
- 0.0.9
- 0.0.8
- 0.0.7
- 0.0.6
- 0.0.5
- 0.0.4
- 0.0.3
- 0.0.2
- dev-renovate/vimeo-psalm-5.x
- dev-renovate/open-feature-flagd-provider-1.x
- dev-renovate/php-8.x
- dev-renovate/spatie-phpunit-snapshot-assertions-5.x
- dev-renovate/phpunit-phpunit-11.x
- dev-release-please--branches--main
- dev-renovate/phpstan-packages
- dev-ci/php83
- dev-feat/events-support
- dev-feat/v0-6-0-support
- dev-feat/php-81-min-version
- dev-feat/support-psr-log-versions
- dev-chore/deprecated-removals
- dev-test/flagd-harness-updates
- dev-chore/revert-test-harness
- dev-renovate/open-feature-sdk-2.x
- dev-chore/integration-update-sdk-version
- dev-ci/integration-update-sdk-version
- dev-fix/provider-resolve-object-interface
- dev-feat/deprecate-php-7
- dev-chore/release-please-reset
- dev-test/coverage-improvements-2
- dev-test/coverage-improvements
- dev-ci/codecov
- dev-test/renaming-test-suite
- dev-chore/deprecate-php-74
- dev-test/integration-init-step
- dev-renovate/open-feature-sdk-1.x
- dev-ci/php-82
- dev-build/upstream-flagd
- dev-renovate/psalm-plugin-mockery-0.x
- dev-docs/provider-info
- dev-ci/integration-tests-and-pr-actions
- dev-beeme1mr-patch-1
This package is auto-updated.
Last update: 2024-09-08 19:16:54 UTC
README
OpenFeature PHP SDK
OpenFeature 是一个开放规范,它提供了一个供应商无关、社区驱动的 API,用于功能标志,可与您喜欢的功能标志管理工具协同工作。
🚀 快速入门
需求
此库针对 PHP 版本 8.0 及更高版本。只要您系统上有任何兼容版本的 PHP,就应该能够使用 OpenFeature SDK。
此包还包括一个 .tool-versions
文件,用于与 asdf
等版本管理器一起使用。
安装
composer require open-feature/sdk
用法
use OpenFeature\OpenFeatureAPI; use OpenFeature\Providers\Flagd\FlagdProvider; function example() { $api = OpenFeatureAPI::getInstance(); // configure a provider $api->setProvider(new FlagdProvider()); // create a client $client = $api->getClient(); // get a bool flag value $client->getBooleanValue('v2_enabled', false); }
扩展示例
use OpenFeature\OpenFeatureClient; class MyClass { private OpenFeatureClient $client; public function __construct() { $this->client = OpenFeatureAPI::getInstance()->getClient('MyClass'); } public function booleanExample(): UI { // Should we render the redesign? Or the default webpage? if ($this->client->getBooleanValue('redesign_enabled', false)) { return render_redesign(); } return render_normal(); } public function stringExample(): Template { // Get the template to load for the custom new homepage $template = $this->client->getStringValue('homepage_template', 'default-homepage.html'); return render_template($template); } public function numberExample(): array { // How many modules should we be fetching? $count = $this->client->getIntegerValue('module-fetch-count', 4); return fetch_modules($count); } public function structureExample(): HomepageModule { $obj = $this->client->getObjectValue('hero-module', $previouslyDefinedDefaultStructure); return HomepageModuleBuilder::new() ->title($obj->getValue('title')) ->body($obj->getValue('description')) ->build(); } }
🌟 功能
已实现:✅ | 进行中:⚠️ | 尚未实现:❌
提供者
提供者 是一个抽象层,位于标志管理系统和 OpenFeature SDK 之间。查看此处以获取可用的提供者的完整列表。如果您正在寻找的提供者尚未创建,请参阅开发提供者部分以了解如何自行构建。
一旦将提供者添加为依赖项,就可以像这样将其注册到 OpenFeature 中
$api = OpenFeatureAPI::getInstance(); $api->setProvider(new MyProvider());
定位
有时,标志的值必须考虑与应用程序或用户的一些动态标准,例如用户的地理位置、IP、电子邮件地址或服务器的位置。在 OpenFeature 中,我们将其称为 定位。如果您正在使用的标志管理系统支持定位,您可以使用 评估上下文 提供输入数据。
// add a value to the global context $api = OpenFeatureAPI::getInstance(); $api->setEvaluationContext(new EvaluationContext('targetingKey', ['myGlobalKey' => 'myGlobalValue'])); // add a value to the client context $client = $api->getClient(); $client->setEvaluationContext(new EvaluationContext('targetingKey', ['myClientKey' => 'myClientValue'])); // add a value to the invocation context $context = new EvaluationContext('targetingKey', ['myInvocationKey' => 'myInvocationValue']); $boolValue = $client->getBooleanValue('boolFlag', false, $context);
钩子
钩子 允许在标志评估生命周期的定义良好的点上添加自定义逻辑。查看此处以获取可用的钩子的完整列表。如果您正在寻找的钩子尚未创建,请参阅开发钩子部分以了解如何自行构建。
一旦将钩子添加为依赖项,就可以在全局、客户端或标志调用级别进行注册。
// add a hook globally, to run on all evaluations $api = OpenFeatureAPI::getInstance(); $api->addHook(new ExampleGlobalHook()); // add a hook on this client, to run on all evaluations made by this client $client = $api->getClient(); $client->addHook(new ExampleClientHook()); // add a hook for this evaluation only $value = $client->getBooleanValue("boolFlag", false, $context, new EvaluationOptions([new ExampleInvocationHook()]));
日志记录
PHP SDK 使用了多个 PHP 标准建议,其中之一是 PSR-3,它提供了一个标准的 LoggerInterface
。SDK 在几个组件上使用了 LoggerAwareTrait
,包括用于标志评估的客户端、钩子执行器和全局 OpenFeatureAPI
实例。当 API 创建 OpenFeature 客户端时,它将自动使用 API 中的配置记录器。客户端中设置的记录器也将自动用于钩子执行。
⚠️ 一旦客户端实例化后,API 日志器的更新将不会同步。这样做是为了支持命名客户端的分离。如果您必须更新现有客户端的日志器,请直接更新!
$api = OpenFeatureAPI::getInstance(); $logger = new FancyLogger(); $defaultLoggerClient = $api->getClient('default-logger'); $api->setLogger(new CustomLogger()); $customLoggerClient = $api->getClient('custom-logger'); $overrideLoggerClient = $api->getClient('override-logger'); $overrideLoggerClient->setLogger($logger); // now let's do some evaluations with these! $defaultLoggerClient->getBooleanValue('A', false); // uses default logger in the SDK $customLoggerClient->getBooleanValue('B', false); // uses the CustomLogger set in the API before the client was made $overrideLoggerClient->getBooleanValue('C', false); // uses the FancyLogger set directly on the client
命名客户端
在 PHP SDK 中尚未提供命名客户端。您可以在此跟踪该功能的进展 这里。
事件处理
在 PHP SDK 中尚未提供事件处理功能。您可以在此跟踪该功能的进展 这里。
关闭
PHP SDK 中尚未提供关闭方法。您可以在此跟踪该功能的进展 这里。
扩展
开发提供者
要开发提供者,您需要创建一个新项目并将 OpenFeature SDK 作为依赖项包含在内。这可以是新存储库或包含在 OpenFeature 组织下的现有 contrib 存储库 中。然后,您需要通过实现 OpenFeature SDK 导出的 Provider
接口来编写提供者。
declare(strict_types=1); namespace OpenFeature\Example\Providers; use OpenFeature\implementation\common\Metadata; use OpenFeature\interfaces\common\Metadata as IMetadata; use OpenFeature\interfaces\flags\EvaluationContext; use OpenFeature\interfaces\hooks\Hook; use OpenFeature\interfaces\provider\Provider; use OpenFeature\interfaces\provider\ResolutionDetails; class ExampleProviderImplementation implements Provider { public function setLogger(LoggerInterface $logger): void { $this->logger = $logger; // or, utilize the OpenFeature\interfaces\common\LoggerAwareTrait } /** * @return Hook[] */ public function getHooks(): array { return $this->hooks; // implement according to the OpenFeature specification } /** * Returns the metadata for the current resource */ public function getMetadata(): IMetadata { return new Metadata(self::class); } public function resolveBooleanValue(string $flagKey, bool $defaultValue, ?EvaluationContext $context = null): ResolutionDetails { // resolve some ResolutionDetails } public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetails { // resolve some ResolutionDetails } public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetails { // resolve some ResolutionDetails } public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetails { // resolve some ResolutionDetails } /** * @inheritdoc */ public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetails { // resolve some ResolutionDetails } }
如您所见,这最终需要一些样板代码来实现提供者期望的所有功能。实现提供者的另一种选项是利用 AbstractProvider 基类。这提供了一些内部连接和简单的脚手架,这样您就可以跳过其中一些内容,并专注于最重要的内容:解析功能标志!
declare(strict_types=1); namespace OpenFeature\Example\Providers; use OpenFeature\interfaces\flags\EvaluationContext; use OpenFeature\interfaces\provider\ResolutionDetails; class ExampleProviderExtension extends AbstractProvider { protected static string $NAME = self::class; public function resolveBooleanValue(string $flagKey, bool $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface { // resolve some ResolutionDetails } public function resolveStringValue(string $flagKey, string $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface { // resolve some ResolutionDetails } public function resolveIntegerValue(string $flagKey, int $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface { // resolve some ResolutionDetails } public function resolveFloatValue(string $flagKey, float $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface { // resolve some ResolutionDetails } /** * @inheritdoc */ public function resolveObjectValue(string $flagKey, array $defaultValue, ?EvaluationContext $context = null): ResolutionDetailsInterface { // resolve some ResolutionDetails } }
已构建新的提供者? 告诉我们,这样我们就可以将其添加到文档中!
开发钩子
要开发钩子,您需要创建一个新项目并将 OpenFeature SDK 作为依赖项包含在内。这可以是新存储库或包含在 OpenFeature 组织下的现有 contrib 存储库 中。通过符合 Hook interface
实现自己的钩子。为了满足接口,需要定义所有方法(Before
/After
/Finally
/Error
)。为了避免定义空函数,请使用 UnimplementedHook
结构(该结构已经实现了所有空函数)。
declare(strict_types=1); namespace OpenFeature\Example\Hooks; use OpenFeature\interfaces\flags\EvaluationContext; use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\Hook; use OpenFeature\interfaces\hooks\HookContext; use OpenFeature\interfaces\hooks\HookHints; use OpenFeature\interfaces\provider\ResolutionDetails; class ExampleStringHookImplementation implements Hook { public function before(HookContext $context, HookHints $hints): ?EvaluationContext { } public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void { } public function error(HookContext $context, Throwable $error, HookHints $hints): void { } public function finally(HookContext $context, HookHints $hints): void { } public function supportsFlagValueType(string $flagValueType): bool { return $flagValueType === FlagValueType::STRING; } }
您还可以使用现有基类来实现各种类型和行为。假设您想创建相同的钩子,并且没有扩展基类的限制,您可以这样做
declare(strict_types=1); namespace OpenFeature\Example\Hooks; use OpenFeature\implementation\hooks\StringHook; use OpenFeature\interfaces\flags\EvaluationContext; use OpenFeature\interfaces\flags\FlagValueType; use OpenFeature\interfaces\hooks\HookContext; use OpenFeature\interfaces\hooks\HookHints; use OpenFeature\interfaces\provider\ResolutionDetails; class ExampleStringHookExtension extends StringHook { public function before(HookContext $context, HookHints $hints): ?EvaluationContext { } public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void { } public function error(HookContext $context, Throwable $error, HookHints $hints): void { } public function finally(HookContext $context, HookHints $hints): void { } }
已构建新的钩子? 告诉我们,这样我们就可以将其添加到文档中!
⭐️ 支持项目
- 给这个仓库一个 ⭐️!
- 在社交媒体上关注我们
- Twitter: @openfeature
- LinkedIn: OpenFeature
- 在 Slack 上加入我们
- 更多信息,请查看我们的 社区页面
🤝 贡献
有兴趣贡献?太好了,我们非常乐意您的帮助!要开始,请查看 CONTRIBUTING 指南。
感谢所有已经做出贡献的人
使用 contrib.rocks 制作。