定制 ajgarlag/feature-flag-bundle 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

ajgarlag/feature-flag-bundle

Composer 安装命令:

composer require ajgarlag/feature-flag-bundle

包简介

Provides a feature flag mechanism

README 文档

README

The FeatureFlag Bundle allows you to split the code execution flow by enabling features depending on context.

It provides a service that checks if a feature is enabled. Each feature is defined by a callable function that returns a value. The feature is enabled if the value matches the expected one (mostly a boolean but not limited to).

This bundle code has been borrowed from symfony/symfony#53213.

Important

The purpose of this bundle is to allow you to test the code proposed in the PR.

🚀 Getting Started

Follow these steps to install and use the bundle in your Symfony application.

Step 1: Download the bundle

Open a command console, enter your project directory and execute the following command to download the latest stable version of this bundle:

composer require ajgarlag/feature-flag-bundle

Step 2: Enable the bundle (for non-Flex applications)

Then, enable the bundle by adding it to the list of registered bundles in the config/bundles.php file of your project:

// config/bundles.php

return [
    // ...
    Ajgarlag\FeatureFlagBundle\FeatureFlagBundle::class => ['all' => true],
];

✨ Declaring features with attributes

You can declare features using the #[AsFeature] attribute. This allows you to autoconfigure your features as services.

On a class

You can use the attribute on an invokable class:

namespace App\Feature;

use Ajgarlag\FeatureFlagBundle\Attribute\AsFeature;

#[AsFeature('xmas')]
final class XmasFeature
{
    public function __invoke(): bool
    {
        return date('m-d') === '12-25';
    }
}

The feature will be named xmas. If you don't provide a name, the FQCN of the class will be used.

You can also use the method property of the attribute to specify a method to call on the service.

namespace App\Feature;

use Ajgarlag\FeatureFlagBundle\Attribute\AsFeature;

#[AsFeature('xmas', method: 'isXmas')]
final class XmasFeature
{
    public function isXmas(): bool
    {
        return date('m-d') === '12-25';
    }
}

On a method

You can also use the attribute on a method of a service. The method must be public.

namespace App\Feature;

use Ajgarlag\FeatureFlagBundle\Attribute\AsFeature;

final class FeatureService
{
    #[AsFeature('weekend')]
    public function isWeekend(): bool
    {
        return date('N') >= 6;
    }

    #[AsFeature] // The feature will be named "App\Feature\FeatureService::isAnotherFeature"
    public function isAnotherFeature(): bool
    {
        return true;
    }
}

🗺️ Routing integration

The bundle provides two functions to use in route conditions: feature_is_enabled and feature_get_value.

You can use them to enable or disable routes based on features.

namespace App\Controller;

use Symfony\Component\Routing\Attribute\Route;

class SomeController
{
    #[Route('/some/path', condition: "feature_is_enabled('some_feature')")]
    public function index()
    {
        // ...
    }
}

You can also use feature_get_value to check for a specific value.

namespace App\Controller;

use Symfony\Component\Routing\Attribute\Route;

class SomeController
{
    #[Route('/some/path', condition: "feature_get_value('some_feature') == 'some_value'")]
    public function index()
    {
        // ...
    }
}

🧩 Providers

Providers are responsible for returning the feature callables. You can create your own provider by implementing the ProviderInterface.

Any service that implements ProviderInterface is automatically registered as a provider. The bundle comes with a ChainProvider that allows you to combine multiple providers. The first provider that returns a feature wins.

The ProviderInterface

To create your own provider, you need to implement the ProviderInterface.

namespace App\FeatureProvider;

use Ajgarlag\FeatureFlagBundle\Provider\ProviderInterface;

class MyProvider implements ProviderInterface
{
    public function get(string $featureName): ?callable
    {
        // ...
    }
}

The get method must return a callable if the provider has the feature, or null otherwise.

Doctrine example
namespace App\FeatureProvider;

use App\Repository\FeatureAssignmentRepository;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use Symfony\Component\FeatureFlag\Provider\ProviderInterface;

final class DoctrineProvider implements ProviderInterface
{
    public function __construct(
        private readonly FeatureAssignmentRepository $featureAssignmentRepository,
    ) {
    }

    public function get(string $featureName): ?callable
    {
        // Set context. Example: user identifier, IP, hostname, etc. 
        $context = [];
        
        return function () use ($featureName) {
            return $this->featureAssignmentRepository->featureIsEnabled($featureName, $context);
        };
    }
}
Gitlab example

First, declare a service to interact with the Unleash API.

// config/services.php

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\Cache\Psr16Cache;
use Unleash\Client\Unleash;
use Unleash\Client\UnleashBuilder;

return function(ContainerConfigurator $container): void {
    
    // Application service definition

    $services->set('gitlab.client_factory')
        ->class(UnleashBuilder::class)
        ->factory([UnleashBuilder::class, 'createForGitlab'])
        ->call('withGitlabEnvironment', [env('GITLAB_ENVIRONMENT')], true)
        ->call('withAppUrl', [env('GITLAB_URL')], true)
        ->call('withInstanceId', [env('GITLAB_INSTANCE_ID')], true)
        ->call('withHttpClient', [service('psr18.http_client')], true)
        // Using a cache is recommended to limit API calls (named "cache.unleash" in this example)
        ->call('withCacheHandler', [inline_service(Psr16Cache::class)->args([service('cache.unleash')])], true)
    ;

    $services->set('gitlab.client')
        ->class(Unleash::class)
        ->factory([service('gitlab.client_factory'), 'build'])
    ;
};
namespace App\FeatureProvider;

use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\FeatureFlag\Provider\ProviderInterface;
use Unleash\Client\Configuration\Context;
use Unleash\Client\Configuration\UnleashContext;
use Unleash\Client\Unleash;

class GitlabProvider implements ProviderInterface
{
    public function __construct(
        #[Autowire(service: 'gitlab.client')] private readonly Unleash $unleash,
        private readonly Security $security,
    ) {
    }

    public function get(string $featureName): ?callable
    {
        // Set context. Example: user identifier, IP, hostname, etc. 
        $context = new UnleashContext(
            currentUserId: $this->security->getUser()?->getUserIdentifier()
        );
        
        return fn () => $this->unleash->isEnabled($featureName, $context);
    }
}

Priority

You can control the order of the providers in the chain using the priority attribute on the ajgarlag.feature_flag.provider tag.

You can use the #[AutoconfigureTag] attribute to set the priority of your provider.

namespace App\FeatureProvider;

use Ajgarlag\FeatureFlagBundle\Provider\ProviderInterface;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('ajgarlag.feature_flag.provider', ['priority' => 10])]
class MyProvider implements ProviderInterface
{
    // ...
}

Providers with a higher priority will be checked first.

🎨 Twig extension

The bundle provides two functions to use in Twig templates: feature_is_enabled and feature_get_value.

{% if feature_is_enabled('some_feature') %}
    {# ... #}
{% endif %}

{% if feature_get_value('some_feature') == 'some_value' %}
    {# ... #}
{% endif %}

ajgarlag/feature-flag-bundle 适用场景与选型建议

ajgarlag/feature-flag-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 20.49k 次下载、GitHub Stars 达 14, 最近一次更新时间为 2025 年 08 月 14 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「flag」 「flags」 「feature」 「toggle」 「ab test」 「rollout」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 ajgarlag/feature-flag-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 ajgarlag/feature-flag-bundle 我们能提供哪些服务?
定制开发 / 二次开发

基于 ajgarlag/feature-flag-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 20.49k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 14
  • 点击次数: 32
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 14
  • Watchers: 1
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-08-14