Фича-флаги в PHP: как переключать функционал без боли и деплоя

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Feature flags в PHP: переключаем фичи без деплоя и молитв

Представьте: вы выкатили новую фичу — и всё сломалось. Сайт лёг, клиенты в панике, девопсы чешут репу. Знакомо? А теперь представьте, что вы можете включить эту фичу только для 5% пользователей, посмотреть на метрики, а если что-то пошло не так — просто щёлкнуть тумблером и откатить. Без деплоя, без коммитов, без боли. Это не магия, это feature flags в PHP.

Feature flags (они же фича-флаги или feature toggles) — это техника, которая позволяет включать и выключать функциональность приложения без изменения кода и повторного деплоя. Звучит как суперсила? Так оно и есть. В этой статье мы разберём, как внедрить управление функционалом PHP в реальных проектах: от простого конфига до интеграции с Symfony и Laravel. Поехали!

Зачем нужны feature flags в PHP-проектах?

Допустим, вы пишете интернет-магазин на PHP. Заказчик просит добавить новый платёжный шлюз. Вы пишете код, тестируете локально, но на проде — сюрприз: шлюз работает нестабильно. Обычно это значит: срочный фикс, ночной деплой, нервный тимлид. С фича-флагами всё иначе. Вы просто выключаете флаг, и старый платёжный шлюз продолжает работать, пока вы спокойно чините баг.

Когда feature flags особенно полезны:

  • Canary releases (канареечные релизы) — включаем фичу для 1% пользователей, потом для 10%, потом для всех.
  • A/B тестирование — показываем разным группам разный функционал и сравниваем конверсию.
  • Отключение сломанного функционала — баг на проде? Выключаем флаг, не откатывая весь релиз.
  • Поэтапный rollout — выкатываем фичу постепенно, чтобы не нагрузить сервера.

И самое главное: feature flags в PHP снижают риск деплоя. Вы перестаёте бояться коммитить в пятницу вечером (ну, почти).

Простейшая реализация: конфиг-файл

Начнём с базы. Самый простой способ — хранить флаги в конфигурационном файле. Например, в формате PHP-массива или JSON.

// config/features.php
return [
    'new_checkout' => false,
    'dark_mode'    => true,
    'ai_recommendations' => false,
];

Используем в коде:

// src/CheckoutService.php
$features = require __DIR__ . '/config/features.php';

if ($features['new_checkout']) {
    // Новая логика оформления заказа
    $this->processWithNewGateway();
} else {
    // Старая логика
    $this->processWithOldGateway();
}

Минус очевиден: чтобы изменить флаг, нужно редактировать файл на сервере. Это неудобно и небезопасно. Но для маленьких проектов — сойдёт. Главное, вы поняли принцип: фича флаги PHP — это просто условные операторы, завязанные на внешнее хранилище.

Продвинутый уровень: хранение в базе данных

Когда проект растёт, конфиг-файл становится узким местом. Хочется управлять флагами через админку. Тут на помощь приходит база данных.

Создаём простую таблицу:

CREATE TABLE feature_flags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) UNIQUE NOT NULL,
    enabled TINYINT(1) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

И пишем простой сервис для работы с флагами:

class FeatureFlagService
{
    private PDO $pdo;
    private array $cache = [];

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function isEnabled(string $flagName): bool
    {
        if (!isset($this->cache[$flagName])) {
            $stmt = $this->pdo->prepare(
                'SELECT enabled FROM feature_flags WHERE name = ?'
            );
            $stmt->execute([$flagName]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $this->cache[$flagName] = $row ? (bool)$row['enabled'] : false;
        }
        return $this->cache[$flagName];
    }

    public function setFlag(string $flagName, bool $enabled): void
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO feature_flags (name, enabled) 
             VALUES (?, ?) 
             ON DUPLICATE KEY UPDATE enabled = ?'
        );
        $stmt->execute([$flagName, $enabled, $enabled]);
        $this->cache[$flagName] = $enabled;
    }
}

Теперь вы можете добавить простую админ-панель, где менеджер включает или выключает фичи. Без деплоя, без кода. Управление функционалом PHP становится делом нескольких кликов.

Feature flags в Symfony: готовое решение

Symfony — это фреймворк, который любит всё из коробки. Для фича-флагов у него есть специальный компонент symfony/feature-flags (доступен с Symfony 6.4). Но если вы на более старой версии, используйте пакет qandidate/toggle или opensolid/feature-flags-bundle.

Пример интеграции с Symfony 7:

// config/packages/feature_flags.yaml
feature_flags:
    flags:
        new_checkout:
            default: false
        dark_mode:
            default: true
    storage: 'database' # или 'config', 'redis'

В контроллере используем сервис:

use Symfony\Component\FeatureFlags\FeatureFlags;

class CheckoutController extends AbstractController
{
    public function __construct(
        private FeatureFlags $featureFlags
    ) {}

    public function checkout(): Response
    {
        if ($this->featureFlags->isEnabled('new_checkout')) {
            // Новая логика
        } else {
            // Старая логика
        }
    }
}

В шаблонах Twig тоже можно проверять:

{% if feature_flag('dark_mode') %}
    <link rel="stylesheet" href="dark.css">
{% endif %}

Красота! Feature flags Symfony — это элегантно и гибко. Единственное: не забывайте кешировать запросы к БД, иначе каждый запрос будет долбить базу.

Feature flags в Laravel: просто и мощно

Laravel тоже не отстаёт. Есть официальный пакет laravel/feature-flags (начиная с Laravel 11), а также популярный pennant — лёгкая библиотека от Laravel-команды.

Установка:

composer require laravel/pennant
php artisan vendor:publish --provider="Laravel\Pennant\PennantServiceProvider"                

Блоги

Рекомендаций по книгам