Docker-Compose环境变量在PHP内置Web服务器中无法读取的问题
问题描述
为复现问题,通过Dockerfile搭建了一个使用PHP内置服务器的Laravel示例应用,Dockerfile内容如下:
FROM composer:latest WORKDIR /var/www/html RUN composer create-project laravel/laravel . --no-dev RUN mv ./.env.example .env RUN php artisan key:generate RUN echo "<?php Route::get('test', fn() => dump(getenv('MY_ENV')));" > routes/api.php CMD php artisan serve --host 0.0.0.0
随后在docker-compose.yml中定义了MY_ENV=123环境变量,配置如下:
version: "3.8" services: laravel: build: . tty: true ports: - '8000:8000' environment: MY_ENV: 123
执行docker compose up -d启动服务后,访问localhost:8000/api/test,发现getenv('MY_ENV')返回false,但预期值为123。有趣的是,在Laravel Tinker中该变量却可以正常读取。
问题原因
- PHP内置服务器的环境变量重置机制:
php artisan serve本质是调用PHP内置开发服务器(php -S),该服务器在处理每个HTTP请求时,会重置当前进程的环境变量集合,仅保留CGI规范定义的标准环境变量(如HTTP_HOST、REQUEST_URI等),自定义的MY_ENV会被清除,因此在请求处理流程中用getenv()读取不到。 - Tinker与Serve的执行差异:
php artisan tinker是直接在启动命令的进程中执行交互逻辑,不会触发内置服务器的环境变量重置操作,因此能正常读取到docker-compose设置的系统环境变量。 - Laravel环境变量加载逻辑:Laravel在框架启动阶段会通过Dotenv组件加载所有环境变量(包括系统级和
.env文件中的)并缓存到内存中,因此使用Laravel自带的env()助手函数可以读取到值,但getenv()是直接读取当前进程的实时环境变量,受内置服务器的重置影响而失效。
解决办法
- 替换为Laravel的
env()助手函数:将代码中的getenv('MY_ENV')改为env('MY_ENV'),利用Laravel缓存的环境变量数据,不受内置服务器的环境变量重置影响。 - 避免在开发/生产环境使用
php artisan serve:生产环境建议使用Nginx+PHP-FPM的标准部署架构,该架构下环境变量会被完整保留,getenv()可以正常读取。 - 将环境变量写入
.env文件:如果坚持使用getenv(),可以在Dockerfile中添加步骤将环境变量写入.env文件,或者在启动命令中显式传递(但仍需注意内置服务器的限制)。
内容的提问来源于stack exchange,提问作者Mwthreex
相关产品推荐
相关产品推荐

