PHP部署时环境区分方案

wen PHP项目 1

本文目录导读:

PHP部署时环境区分方案

  1. 环境变量方案(最推荐)
  2. 服务器配置区分
  3. 基于主机名自动判断(简单场景)
  4. 配置文件分层方案
  5. 完整实践案例(推荐生产架构)
  6. 部署时的自动化切换
  7. 最佳实践建议

在PHP部署中,环境区分(开发、测试、生产)是一个核心问题,以下是几种主流且实践性强的方案,按推荐程度排序:

环境变量方案(最推荐)

使用 .env 文件 + getenv()

// .env 文件(不同环境使用不同文件)
// .env.development
APP_ENV=development
APP_DEBUG=true
DB_HOST=localhost
DB_DATABASE=dev_db
// .env.production  
APP_ENV=production
APP_DEBUG=false
DB_HOST=192.168.1.100
DB_DATABASE=prod_db
// 加载对应环境的 .env 文件
$envFile = '.env.' . (getenv('APP_ENV') ?: 'development');
if (file_exists($envFile)) {
    $lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (strpos($line, '=') !== false) {
            list($key, $value) = explode('=', $line, 2);
            putenv("$key=$value");
        }
    }
}
// 使用配置
$dbHost = getenv('DB_HOST');

使用 Dotenv 库(推荐生产使用)

// 安装:composer require vlucas/phpdotenv
use Dotenv\Dotenv;
// 根据服务器环境变量加载对应文件
$appEnv = $_SERVER['APP_ENV'] ?? 'development';
$dotenv = Dotenv::create(__DIR__, ".env.$appEnv");
$dotenv->load();

服务器配置区分

Nginx 配置

# 开发环境
server {
    server_name dev.example.com;
    fastcgi_param APP_ENV development;
}
# 生产环境
server {
    server_name example.com;
    fastcgi_param APP_ENV production;
}

Apache 配置

SetEnv APP_ENV development
# 或
SetEnvIf Host "dev\.example\.com" APP_ENV=development

基于主机名自动判断(简单场景)

class EnvironmentDetector {
    public static function detect() {
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        // 规则化匹配
        if (strpos($host, 'localhost') !== false || strpos($host, '127.0.0.1') !== false) {
            return 'development';
        }
        if (strpos($host, 'staging.') === 0) {
            return 'staging';
        }
        if (strpos($host, 'dev.') === 0) {
            return 'development';
        }
        return 'production';
    }
}
$environment = EnvironmentDetector::detect();

配置文件分层方案

// config/base.php - 公共配置
return [
    'app_name' => 'My App',
    'timezone' => 'Asia/Shanghai',
];
// config/development.php
return [
    'debug' => true,
    'log_level' => 'debug',
    'database' => [
        'host' => 'localhost',
        'database' => 'dev_db',
    ],
];
// config/production.php
return [
    'debug' => false,
    'log_level' => 'error',
    'database' => [
        'host' => 'production-db.example.com',
        'database' => 'prod_db',
    ],
];
// 配置加载器
class ConfigLoader {
    public static function load($environment) {
        $base = require __DIR__ . '/config/base.php';
        $envConfig = __DIR__ . '/config/' . $environment . '.php';
        if (file_exists($envConfig)) {
            return array_merge($base, require $envConfig);
        }
        return $base;
    }
}

完整实践案例(推荐生产架构)

<?php
// bootstrap.php
class Environment {
    private static $instance = null;
    private $config = [];
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    private function __construct() {
        $this->detectEnvironment();
        $this->loadConfiguration();
    }
    private function detectEnvironment() {
        // 优先级:服务器变量 > 环境变量 > 域名判断
        $this->environment = getenv('APP_ENV') 
            ?: $_SERVER['APP_ENV']
            ?: $this->detectByHost()
            ?: 'production';
    }
    private function detectByHost() {
        $host = $_SERVER['HTTP_HOST'] ?? '';
        if (strpos($host, 'localhost') !== false) {
            return 'development';
        }
        if (strpos($host, 'staging') !== false) {
            return 'staging';
        }
        return null;
    }
    private function loadConfiguration() {
        $configDir = __DIR__ . '/config/';
        // 加载全局配置
        $globalConfig = require $configDir . 'global.php';
        // 加载环境特定配置
        $envFile = $configDir . $this->environment . '.php';
        if (file_exists($envFile)) {
            $envConfig = require $envFile;
        } else {
            $envConfig = [];
        }
        $this->config = array_merge($globalConfig, $envConfig);
    }
    public function get($key = null) {
        if ($key === null) {
            return $this->config;
        }
        return $this->config[$key] ?? null;
    }
    public function isProduction() {
        return $this->environment === 'production';
    }
    public function isDebug() {
        return $this->config['debug'] ?? false;
    }
}

部署时的自动化切换

# deploy.yml (部署工具配置示例)
environments:
  development:
    server: dev-server
    env_file: .env.development
    php_version: 7.4
  staging:
    server: staging-server
    env_file: .env.staging
    php_version: 8.0
  production:
    server:
      - web1.example.com
      - web2.example.com
    env_file: .env.production
    php_version: 8.1
    optimize: true
# 部署脚本示例
#!/bin/bash
ENVIRONMENT=$1
case $ENVIRONMENT in
    development)
        cp .env.development .env
        php artisan config:cache
        ;;
    staging)
        cp .env.staging .env
        php artisan config:cache
        php artisan migrate --force
        ;;
    production)
        cp .env.production .env
        php artisan config:cache
        php artisan route:cache
        php artisan view:cache
        php artisan migrate --force
        ;;
esac

最佳实践建议

  1. 敏感信息不提交到代码库:将 .env.production 加入 .gitignore
  2. 配置优先级:环境变量 > 配置文件 > 代码默认值
  3. 日志分级:根据环境调整日志级别
  4. 错误处理:生产环境隐藏错误详情,开发环境显示
  5. 自动检测+手动覆盖:多策略综合判断

选择哪种方案取决于项目复杂度,小型项目用简单的域名判断即可,大型项目建议使用环境变量 + 配置文件分层方案。

抱歉,评论功能暂时关闭!