本文目录导读:

在 PHP 项目中实现功能开关(Feature Flag)有多种方式,从简单到复杂,以下是几种常见方案:
最简单的配置常量方式
// config/features.php
return [
'new_checkout' => true,
'dark_mode' => false,
'beta_features' => false
];
// 使用方法
$features = require 'config/features.php';
if ($features['new_checkout']) {
// 新结账流程
} else {
// 旧结账流程
}
数据库驱动的方式
// 创建功能开关表
CREATE TABLE feature_flags (
id INT PRIMARY KEY AUTO_INCREMENT,
feature_name VARCHAR(100) UNIQUE,
is_enabled BOOLEAN DEFAULT false,
description VARCHAR(255),
updated_at TIMESTAMP
);
// 封装为类
class FeatureManager {
private $db;
private $cache = [];
public function __construct(PDO $db) {
$this->db = $db;
$this->loadFeatures();
}
private function loadFeatures() {
$stmt = $this->db->query("SELECT feature_name, is_enabled FROM feature_flags");
while ($row = $stmt->fetch()) {
$this->cache[$row['feature_name']] = (bool)$row['is_enabled'];
}
}
public function isEnabled($featureName) {
return isset($this->cache[$featureName]) ? $this->cache[$featureName] : false;
}
}
// 使用示例
$featureManager = new FeatureManager($pdo);
if ($featureManager->isEnabled('new_checkout')) {
// 新功能代码
}
使用配置文件 + 环境变量
// config/features.php
return [
'new_checkout' => getenv('FEATURE_NEW_CHECKOUT') !== false
? filter_var(getenv('FEATURE_NEW_CHECKOUT'), FILTER_VALIDATE_BOOLEAN)
: true,
'dark_mode' => getenv('FEATURE_DARK_MODE') !== false
? filter_var(getenv('FEATURE_DARK_MODE'), FILTER_VALIDATE_BOOLEAN)
: false
];
使用现成的库
Laravel 环境
// 使用 laravel-feature-flag 包
composer require laravel-feature-flag/laravel-feature-flag
// 使用示例
use LaravelFeatureFlag\FeatureFlag;
if (FeatureFlag::isEnabled('new_checkout')) {
// 新结账流程
}
独立库
// 使用 php-feature-flags 等库
composer require php-feature-flags/php-feature-flags
// 初始化和使用
$lookup = new RedisFeatureFlagLookup($redis);
$flags = new FeatureFlags($lookup);
if ($flags->isOn('new_checkout')) {
// 新功能代码
}
高级特性:百分比发布 + 用户分组
class PercentFeature {
private $featureName;
private $percent;
public function __construct($featureName, $percent) {
$this->featureName = $featureName;
$this->percent = $percent;
}
public function isEnabled($userId) {
// 使用用户ID作为种子,确保同一用户始终看到同一版本
$hash = crc32($userId . '-' . $this->featureName);
return ($hash % 100) < $this->percent;
}
}
// 使用示例
$newCheckout = new PercentFeature('new_checkout', 20); // 20%的用户
if ($newCheckout->isEnabled($userId)) {
// 新结账流程(面向20%用户)
}
完整的集成示例
<?php
class FeatureFlagService {
private $config;
private $cache = [];
private $db;
public function __construct(PDO $db = null) {
$this->db = $db;
$this->config = require 'config/features.php';
}
public function isEnabled($feature, $userId = null) {
// 检查缓存
$cacheKey = $feature . (isset($userId) ? ":{$userId}" : '');
if (isset($this->cache[$cacheKey])) {
return $this->cache[$cacheKey];
}
$enabled = $this->checkConfig($feature); // 基础配置
$enabled = $this->checkDatabase($feature, $enabled); // 数据库覆盖
$enabled = $this->checkUserGroup($feature, $userId, $enabled); // 用户分组
// 缓存结果
$this->cache[$cacheKey] = $enabled;
return $enabled;
}
private function checkConfig($feature) {
return isset($this->config[$feature]) ? $this->config[$feature] : false;
}
private function checkDatabase($feature, $default) {
// 从数据库获取配置,如果没找到则返回默认值
return $default;
}
private function checkUserGroup($feature, $userId, $default) {
// 实现百分百发布或用户分组逻辑
return $default;
}
}
// 使用示例
$featureFlags = new FeatureFlagService($pdo);
// 在业务代码中
if ($featureFlags->isEnabled('new_checkout', $currentUserId)) {
// 新结账流程
} else {
// 旧结账流程
}
最佳实践建议
- 默认关闭:新功能默认关闭,确保安全
- 易于管理:提供管理界面或配置中心
- 日志记录:记录功能开关的使用情况
- 灰度发布:支持分阶段发布(10% → 25% → 50% → 全部)
- 监控和回滚:实时监控功能表现,支持快速回滚
选择哪种方案取决于你的项目规模和需求:
- 小项目使用配置文件
- 中型项目使用数据库
- 大型项目建议使用专业的 Feature Flag 服务(如 LaunchDarkly、Split.io)