PHPackages                             antfroger/progressive - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. antfroger/progressive

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

antfroger/progressive
=====================

The library to progressively, quickly and simply enables new features

v1.2.2(8mo ago)22.9k1MITPHPPHP ^8.1CI passing

Since Dec 10Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/antfroger/progressive)[ Packagist](https://packagist.org/packages/antfroger/progressive)[ Docs](https://github.com/antfroger/Progressive)[ RSS](/packages/antfroger-progressive/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)Dependencies (2)Versions (7)Used By (1)

Progressive
===========

[](#progressive)

Progressive is a feature flag library *(also called toggle, switch, ...)*.
Thanks to Progressive, you can **progressively**, **quickly** and **simply** enable new features. (and just as quickly deactivate them in case of an emergency)

[![Build Status](https://github.com/antfroger/progressive/workflows/CI/badge.svg)](https://github.com/antfroger/progressive)[![Latest Stable Version](https://camo.githubusercontent.com/07a861d1d8554837b98cd234bfad4ef1eed9ffebd71a40a8ac22eb03da0bf866/68747470733a2f2f706f7365722e707567782e6f72672f616e7466726f6765722f70726f67726573736976652f762f737461626c652e706e67)](https://packagist.org/packages/antfroger/progressive "Latest Stable Version")

Installation
------------

[](#installation)

```
$ composer require antfroger/progressive
```

Usage
-----

[](#usage)

```
// From a file
$config = \Symfony\Component\Yaml\Yaml::parseFile('/your-own-config-file.yaml');
// Content of /your-own-config-file.yaml
// features:
//   dark-theme: true
//   call-center: false
//   homepage-v2:
//     enabled: true

// Or from a PHP array
$config = [
    'features' => [
        'dark-theme'  => true,
        'call-center' => false,
        'homepage-v2' => [
            'enabled' => true
        ],
    ]
];

$progressive = new Progressive($config);
$progressive->isEnabled('dark-theme');    // true
$progressive->isEnabled('call-center');   // false
$progressive->isEnabled('homepage-v2');   // true
```

Rules
-----

[](#rules)

### Built-in

[](#built-in)

#### `enabled: true|false`

[](#enabled-truefalse)

`enabled` enables (or disables) the feature for everyone, everywhere, all the time.
The value is meant to be a boolean, `true|false`.

```
// Short
$config = [
    'features' => [
        'dark-theme' => true
    ]
];

// Verbose
$config = [
    'features' => [
        'dark-theme'  => [
            'enabled' => true
        ]
    ]
];
```

### Custom

[](#custom)

You will probably need many more rules that will fit your needs and stack.

Let's say you want to redesign your homepage and progressively displaying it to test if everything goes right.
You start by enabling it in dev, then preprod, then prod but only for developers, then admins, then 1% of the users...
How would you be able to achieve that?

With custom rules!

```
$config = [
    'features' => [
        'homepage-v123'  => [
            'env' => ['DEV', 'PREPROD']
        ]
    ]
];
$progressive = new Progressive($config);

$progressive->addCustomRule('env', function (Context $context, array $envs) {
    return in_array(getenv('ENV'), $envs);
});

$progressive->isEnabled('homepage-v123'); // Returns true if ENV is DEV or PREPROD, otherwise returns false
```

(this lambda can be improved thanks to the `Context object` - more about it [here](#context-object))

Strategies
----------

[](#strategies)

Rules are great but sometimes one rule is not enough to decide if a feature must be enabled.
You may want to enable a feature in `PROD` only for admins but to everyone in `DEV`, `TEST` and `PREPROD`.
Or you may want to enable a feature to the admins **AND** a given percentage of users.

That's where strategies come into play!

*(Strategies are simply another name for nested rules.
And as for rules, you can create your own strategies!)*

Progressive comes with two built-in strategies:

### `unanimous: []`

[](#unanimous-)

`unanimous` enables the feature if **all** the conditions are met.
The value is meant to be an array of [rules](#rules).

```
$config = [
    'features' => [
        'translate-interface'  => [
            'unanimous' => [
                'env'   => ['DEV', 'PREPROD'],
                'roles' => ['ROLE_ADMIN', 'ROLE_TRANSLATOR']
            ]
        ]
    ]
];
```

In this example, the interface to translate the app will only be displayed in `DEV` and `PREPROD` environments to users having `ROLE_ADMIN` or `ROLE_TRANSLATOR` as roles.
This strategy can be defined as an **AND**.

### `partial: []`

[](#partial-)

`partial` enables the feature if only **one** of the conditions is met.
Rules are evaluated one by one. The feature is enabled as soon as one rule is true.
The value is meant to be an array of [rules](#rules).

```
$config = [
    'features' => [
        'translate-interface'  => [
            'partial' => [
                'env'   => ['DEV', 'PREPROD'],
                'roles' => ['ROLE_ADMIN', 'ROLE_TRANSLATOR']
            ]
        ]
    ]
];
```

In this example, the interface to translate the app will be displayed:

- in `DEV` and `PREPROD` environments (for all users)
- for users having a role `ROLE_ADMIN` or `ROLE_TRANSLATOR`, regardless of the environment.

This strategy can be defined as an **OR**.

Context object
--------------

[](#context-object)

Progressive doesn't know anything of your application logic code (and doesn't want to know).
But you may want to use your logic inside custom rules.

In that case, the context object is your friend!
It's nothing more that an user-defined databag.

You can use it to improve our previous custom rule:

```
$context = new Context([
    'env' => getenv('ENV') ?: 'PROD'
]);

$config = [
    'features' => [
        'homepage-v123'  => [
            'env' => ['DEV', 'PREPROD']
        ]
    ]
];

$progressive = new Progressive($config, $context);
$progressive->addCustomRule('env', function (Context $context, array $envs) {
    return in_array($context->get('env'), $envs);
});
```

Another common example is to store the current user in the context:

```
$context = new Context(['user' => $user]);

$config = [
    'features' => [
        'homepage-v123'  => [
            'roles' => ['ROLE_ADMIN']
        ]
    ]
];

$progressive = new Progressive($config, $context);
$progressive->addCustomRule('roles', function (Context $context, array $roles) {
    $userRoles = $context->get('user')->getRoles();
    foreach ($roles as $role) {
        if (in_array($role, $userRoles) {
            return true;
        }
    }

    return false;
});
```

Requesting a non-existing flag
------------------------------

[](#requesting-a-non-existing-flag)

Whenever you request an non-existing flag, `isEnabled` will return false.
The flag is considered disabled.

```
$config = [
    'features' => []
];

$progressive = new Progressive($config);
$progressive->isEnabled('dark-theme'); // false
```

Separate feature releases from code deploy
------------------------------------------

[](#separate-feature-releases-from-code-deploy)

As Progressive takes an array of config, it makes it possible to decorrelate the release calendar from the code deployment.
In this example, we use the Symfony Yaml component to read the config from a YAML file.

```
use Symfony\Component\Yaml\Yaml;

$config = Yaml::parseFile('/your-own-config-file.yaml');
// Content of /your-own-config-file.yaml
// features:
//   new-feature: false
$progressive = new Progressive($config);
$progressive->isEnabled('new-feature'); // false
```

Imagine that you are able to deploy the config files independently from your code base, you could release a new feature without having to deploy all your code base, by redeploying only `/your-own-config-file.yaml`.

```
// Content of /your-own-config-file.yaml
// features:
//   new-feature: true
$progressive->isEnabled('new-feature'); // true
```

You may also want to store the configuration in a database and pass it as an array to Progressive.

Progressive in your projects
----------------------------

[](#progressive-in-your-projects)

- Progressive is also available as a [Symfony bundle](https://github.com/antfroger/progressive-bundle)

---

*Inspired by [Laurent Callarec](https://github.com/lcallarec)'s javascript feature-flag library [Banderole](https://github.com/lcallarec/banderole)*

###  Health Score

45

—

FairBetter than 92% of packages

Maintenance67

Regular maintenance activity

Popularity23

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 91.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~344 days

Recently: every ~428 days

Total

6

Last Release

263d ago

Major Versions

v0.1 → v1.02020-12-18

PHP version history (3 changes)v0.1PHP &gt;=7.3

v1.0PHP ^7.3 || ^8.0

v1.2.2PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/f18ebdd3d6b87dd200daf934cd7c76f0707e4321582f46c603471578320690e8?d=identicon)[antfroger](/maintainers/antfroger)

---

Top Contributors

[![antfroger](https://avatars.githubusercontent.com/u/3509631?v=4)](https://github.com/antfroger "antfroger (31 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (3 commits)")

---

Tags

feature-flagfeature-flagsfeature-togglefeature-togglesphpphp-libphp-library

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/antfroger-progressive/health.svg)

```
[![Health](https://phpackages.com/badges/antfroger-progressive/health.svg)](https://phpackages.com/packages/antfroger-progressive)
```

###  Alternatives

[joshribakoff/php-csv-utils

php-csv-utils

1143.8k1](/packages/joshribakoff-php-csv-utils)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
