Laravel ENV—— 环境变量的加载与源码解析 | Laravel China 社区


本站和网页 https://learnku.com/articles/5638/laravel-env-the-loading-of-environment-variables-and-source-code-analysis 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

Laravel ENV—— 环境变量的加载与源码解析 | Laravel China 社区
Laravel
话题列表
社区 Wiki
优质外文
招聘求职
Laravel 实战教程
社区文档
登录
注册
Laravel
首页
Laravel
Go
PHP
Vue.js
Python
Java
MySQL
Rust
LK
Elasticsearch
F2E 前端
Server
程序员
Database
DevTools
Computer Science
手机开发
AdonisJS
社区
Wiki
教程
Laravel 实战教程首页
《L01 Laravel 教程 - Web 开发实战入门》
《L02 Laravel 教程 - Web 开发实战进阶》
《L03 Laravel 教程 - 实战构架 API 服务器》
《L04 Laravel 教程 - 微信小程序从零到发布》
《L05 Laravel 教程 - 电商实战》
《L06 Laravel 教程 - 电商进阶》
《LX1 Laravel / PHP 扩展包视频教程》
《LX2 PHP 扩展包实战教程 - 从入门到发布》
《L07 Laravel 教程 - Laravel TDD 测试实战》
《LX3 Laravel 性能优化入门》
《LX4 Laravel / PHP 五分钟视频》
文档
社区文档首页
《Laravel 中文文档》
《Laravel 速查表》
《PHP 代码简洁之道》
《Laravel 编码技巧》
《Dcat Admin 中文文档》
《Laravel Nova 中文文档》
《Lumen 中文文档》
《Dingo API 中文文档》
《 Laravel 项目开发规范》
《构建 Laravel 开发环境》
登录
注册
微信登录
Laravel ENV—— 环境变量的加载与源码解析
41
17
11
leoyang 的个人博客
18963
11
创建于 5年前
更新于 4年前
前言
本文 GitBook 地址: https://www.gitbook.com/book/leoyang90/lar...
laravel 在启动时,会加载项目的 env 文件,本文将会详细介绍 env 文件的使用与源码的分析。
ENV 文件的使用
多环境 ENV 文件的设置
laravel 支持在不同的环境下加载不同的 env 文件,若想要实现多环境 env 文件,需要做两件事:
一、在项目写多个 ENV 文件,例如三个 env 文件:
.env.development、
.env.staging、
.env.production,
这三个文件中分别针对不同环境为某些变量配置了不同的值,
二、配置 APP_ENV 环境变量值
配置环境变量的方法有很多,其中一个方法是在 nginx 的配置文件中写下这句代码:
fastcgi_param APP_ENV production;
那么 laravel 会通过 env('APP_ENV') 根据环境变量 APP_ENV 来判断当前具体的环境,假如环境变量 APP_ENV 为 production,那么 laravel 将会自动加载 .env.production 文件。
自定义 ENV 文件的路径与文件名
laravel 为用户提供了自定义 ENV 文件路径或文件名的函数,
例如,若想要自定义 env 路径,就可以在 bootstrap 文件夹中 app.php 文件:
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
$app->useEnvironmentPath('/customer/path')
若想要自定义 env 文件名称,就可以在 bootstrap 文件夹中 app.php 文件:
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
$app->loadEnvironmentFrom('customer.env')
ENV 文件变量设置
在 env 文件中,我们可以为变量赋予具体值:
CFOO=bar
值得注意的是,这种具体值不允许赋予多个,例如:
CFOO=bar baz
可以为变量赋予字符串引用
CQUOTES="a value with a # character"
值得注意的是,这种引用不允许字符串中存在符号 \,只能使用转义字符 \\
而且也不允许内嵌符号 "",只能使用转移字符 \",否则取值会意外结束:
CQUOTESWITHQUOTE="a value with a # character & a quote \" character inside quotes" # " this is a comment
$this->assertEquals('a value with a # character & a quote " character inside quotes', getenv('CQUOTESWITHQUOTE'));
可以在 env 文件中添加注释,方法是以 # 开始:
CQUOTES="a value with a # character" # this is a comment
可以使用 export 来为变量赋值:
export EFOO="bar"
可以在 env 文件中使用变量为变量赋值:
NVAR1="Hello"
NVAR2="World!"
NVAR3="{$NVAR1} {$NVAR2}"
NVAR4="${NVAR1} ${NVAR2}"
NVAR5="$NVAR1 {NVAR2}"
$this->assertEquals('{$NVAR1} {$NVAR2}', $_ENV['NVAR3']); // not resolved
$this->assertEquals('Hello World!', $_ENV['NVAR4']);
$this->assertEquals('$NVAR1 {NVAR2}', $_ENV['NVAR5']); // not resolved
ENV 加载源码分析
laravel 加载 ENV
ENV 的加载功能由类 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class 完成,它的启动函数为:
public function bootstrap(Application $app)
if ($app->configurationIsCached()) {
return;
$this->checkForSpecificEnvironmentFile($app);
try {
(new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
} catch (InvalidPathException $e) {
//
如果我们在环境变量中设置了 APP_ENV 变量,那么就会调用函数 checkForSpecificEnvironmentFile 来根据环境加载不同的 env 文件:
protected function checkForSpecificEnvironmentFile($app)
if (php_sapi_name() == 'cli' && with($input = new ArgvInput)->hasParameterOption('--env')) {
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.$input->getParameterOption('--env')
);
if (! env('APP_ENV')) {
return;
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.env('APP_ENV')
);
protected function setEnvironmentFilePath($app, $file)
if (file_exists($app->environmentPath().'/'.$file)) {
$app->loadEnvironmentFrom($file);
vlucas/phpdotenv 源码解读
laravel 中对 env 文件的读取是采用 vlucas/phpdotenv 的开源项目:
class Dotenv
public function __construct($path, $file = '.env')
$this->filePath = $this->getFilePath($path, $file);
$this->loader = new Loader($this->filePath, true);
public function load()
return $this->loadData();
protected function loadData($overload = false)
$this->loader = new Loader($this->filePath, !$overload);
return $this->loader->load();
env 文件变量的读取依赖类 /Dotenv/Loader:
class Loader
public function load()
$this->ensureFileIsReadable();
$filePath = $this->filePath;
$lines = $this->readLinesFromFile($filePath);
foreach ($lines as $line) {
if (!$this->isComment($line) && $this->looksLikeSetter($line)) {
$this->setEnvironmentVariable($line);
return $lines;
我们可以看到,env 文件的读取的流程:
判断 env 文件是否可读
读取整个 env 文件,并将文件按行存储
循环读取每一行,略过注释
进行环境变量赋值
protected function ensureFileIsReadable()
if (!is_readable($this->filePath) || !is_file($this->filePath)) {
throw new InvalidPathException(sprintf('Unable to read the environment file at %s.', $this->filePath));
protected function readLinesFromFile($filePath)
// Read file into an array of lines with auto-detected line endings
$autodetect = ini_get('auto_detect_line_endings');
ini_set('auto_detect_line_endings', '1');
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
ini_set('auto_detect_line_endings', $autodetect);
return $lines;
protected function isComment($line)
return strpos(ltrim($line), '#') === 0;
protected function looksLikeSetter($line)
return strpos($line, '=') !== false;
环境变量赋值是 env 文件加载的核心,主要由 setEnvironmentVariable 函数:
public function setEnvironmentVariable($name, $value = null)
list($name, $value) = $this->normaliseEnvironmentVariable($name, $value);
if ($this->immutable && $this->getEnvironmentVariable($name) !== null) {
return;
if (function_exists('apache_getenv') && function_exists('apache_setenv') && apache_getenv($name)) {
apache_setenv($name, $value);
if (function_exists('putenv')) {
putenv("$name=$value");
$_ENV[$name] = $value;
$_SERVER[$name] = $value;
normaliseEnvironmentVariable 函数用来加载各种类型的环境变量:
protected function normaliseEnvironmentVariable($name, $value)
list($name, $value) = $this->splitCompoundStringIntoParts($name, $value);
list($name, $value) = $this->sanitiseVariableName($name, $value);
list($name, $value) = $this->sanitiseVariableValue($name, $value);
$value = $this->resolveNestedVariables($value);
return array($name, $value);
splitCompoundStringIntoParts 用于将赋值语句转化为环境变量名 name 和环境变量值 value。
protected function splitCompoundStringIntoParts($name, $value)
if (strpos($name, '=') !== false) {
list($name, $value) = array_map('trim', explode('=', $name, 2));
return array($name, $value);
sanitiseVariableName 用于格式化环境变量名:
protected function sanitiseVariableName($name, $value)
$name = trim(str_replace(array('export ', '\'', '"'), '', $name));
return array($name, $value);
sanitiseVariableValue 用于格式化环境变量值:
protected function sanitiseVariableValue($name, $value)
$value = trim($value);
if (!$value) {
return array($name, $value);
if ($this->beginsWithAQuote($value)) { // value starts with a quote
$quote = $value[0];
$regexPattern = sprintf(
'/^
%1$s # match a quote at the start of the value
( # capturing sub-pattern used
(?: # we do not need to capture this
[^%1$s\\\\] # any character other than a quote or backslash
|\\\\\\\\ # or two backslashes together
|\\\\%1$s # or an escaped quote e.g \"
)* # as many characters that match the previous rules
) # end of the capturing sub-pattern
%1$s # and the closing quote
.*$ # and discard any string after the closing quote
/mx',
$quote
);
$value = preg_replace($regexPattern, '$1', $value);
$value = str_replace("\\$quote", $quote, $value);
$value = str_replace('\\\\', '\\', $value);
} else {
$parts = explode(' #', $value, 2);
$value = trim($parts[0]);
// Unquoted values cannot contain whitespace
if (preg_match('/\s+/', $value) > 0) {
throw new InvalidFileException('Dotenv values containing spaces must be surrounded by quotes.');
return array($name, trim($value));
这段代码是加载 env 文件最复杂的部分,我们详细来说:
若环境变量值是具体值,那么仅仅需要分割注释 # 部分,并判断是否存在空格符即可。
若环境变量值由引用构成,那么就需要进行正则匹配,具体的正则表达式为:
/^"((?:[^"\\]|\\\\|\\"))".*$/mx
这个正则表达式的意思是:
提取 “” 双引号内部的字符串,抛弃双引号之后的字符串
若双引号内部还有双引号,那么以最前面的双引号为提取内容,例如 "dfd("dfd")fdf",我们只能提取出来最前面的部分 "dfd("
对于内嵌的引用可以使用 \" ,例如 "dfd\"dfd\"fdf",我们就可以提取出来 "dfd\"dfd\"fdf"。
不允许引用中含有 \,但可以使用转义字符 \\
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
举报
leoyang
1.0k 声望
暂无个人描述~
41 人点赞
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
推荐文章:
更多推荐...
分享创造
如何找到你的第一份远程工作与海外外包-远程工作篇(放了个TS全栈教学的广告,不喜欢立删...)
33
21
1个月前
翻译
如何在 Laravel 中创建一个简单的事件流?
19
12
3个月前
博客
我是如何把网站图片cdn流量成本压到全网最低(之一)的
32
28
3个月前
博客
🎈 Slow Admin - 使用Laravel和Amis快速构建你的后台
25
35
3个月前
博客
用Go实现支持多种协议的抓包工具——Shermie-Proxy
22
33
5个月前
分享创造
大佬的收藏夹
75
21
5个月前
讨论数量: 11
排序:
时间
投票
lx1036
LaraDinner 01
629 声望
写的很详细啊。
5年前
评论
评论
举报
leoyang
1.0k 声望
@lx1036 :)
5年前
评论
评论
举报
mingyuanyun
7 声望
HR @ 明源云
厉害了 :heart_eyes:
4年前
评论
评论
举报
Jochen-z
课程读者
61 声望
PHPer @ PHP Team
学习了
4年前
评论
评论
举报
Empyy
见习助教
5 声望
执行脚本的时候指定环境, 比如 php artisan command:test --env=production 才对得到正确的配置。若忘记输入配置了, 能不能设置 --env 必须指定的,否则报错提示,不然很容易出状况。
4年前
评论
评论
举报
JJonline
0 声望
解析ini文件,PHP内置的一个parse_ini_file函数就搞定了,非得造轮子,什么原因?
4年前
评论
评论
举报
missing
1 声望
您好,我通过export APP_ENV=tesing 设置了环境变量之后用env('APP_ENV')获取不到是为什呢
3年前
评论
评论
举报
火星上的凡尔赛
课程读者
7 声望
nginx 配置fastcgi_param APP_ENV production就报502 [error] 6344#6592: *52 WSARecv() failed (10054: An existing connection was forcibly closed by the remote host) while reading response header from upstream
3年前
评论
评论
举报
JohnYep
课程读者
10 声望
PHP工程师 @ 零壹新科技(深圳)有限公司
@Empyy 最近刚踩坑啊,crontab测试服总是读取的正式服配置
3年前
评论
评论
举报
Aries-La
0 声望
PHP版本在7.1.13和7.2.10的Bug
2年前
评论
评论
举报
zhaoguangshuai
课程读者
21 声望
@mingyuanyun 人事也跑进来看社区了?
2年前
评论
评论
举报
讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
<a href="javascript:;" class="mr-2 ui popover text-mute" data-html="黏贴或拖拽图片至输入框内皆可上传图片">
<a href="javascript:;" class="mr-2 ui popover text-mute hide-on-mobile" data-html="支持除了 H1~H6 以外的GitHub 兼容 Markdown">
支持 MD
帮助
关注本文
评论
leoyang
未填写
文章
86
粉丝
1168
喜欢
1297
收藏
561
排名:3
访问:79.8 万
关注
私信
所有博文
阅读模式
文章归档
2 篇
2018 年 10 月
10 篇
2018 年 9 月
16 篇
2018 年 8 月
6 篇
2018 年 7 月
11 篇
2018 年 6 月
3 篇
2018 年 1 月
4 篇
2017 年 12 月
1 篇
2017 年 11 月
7 篇
2017 年 10 月
4 篇
2017 年 9 月
8 篇
2017 年 8 月
6 篇
2017 年 7 月
8 篇
2017 年 5 月
最新文章
最受欢迎
4年前
Swoole 源码分析——Client 模块之 Recv
4年前
Swoole 源码分析——Client 模块之 Send
4年前
Swoole 源码分析——Client 模块之 Connect
4年前
Swoole 源码分析——进程管理 Swoole_Process
4年前
Swoole 源码分析——Async 异步事件系统 Swoole_Event
96
Laravel Queue——消息队列任务与分发源码剖析
82
Laravel 核心——IoC 服务容器
71
Laravel Exceptions——异常与错误处理
68
本专栏系列文章已经收录到 GitBook
60
PHP 自动加载功能原理解析
博客标签
php
laravel
swoole
https
openssl
ssl
社区赞助商
成为赞助商
社区赞助商
成为赞助商
关于 LearnKu
LearnKu 是终身编程者的修道场
做最专业、严肃的技术论坛
LearnKu 诞生的故事
资源推荐
《社区使用指南》
《文档撰写指南》
《LearnKu 社区规范》
《提问的智慧》
服务提供商
其他信息
成为版主
所有测验
联系站长(反馈建议)
粤ICP备18099781号-6
粤公网安备 44030502004330号
违法和不良信息举报
由 Summer 设计和编码 ❤
请登录
提交
忘记密码?
or
注册
第三方账号登录
微信登录
GitHub 登录
内容举报
匿名举报,为防止滥用,仅管理员可见举报者。
我要举报该,理由是:
垃圾广告:恶意灌水、广告、推广等内容
无意义内容:测试、灌水、文不对题、消极内容、文章品质太差等
违规内容:色情、暴利、血腥、敏感信息等
不友善内容:人身攻击、挑衅辱骂、恶意行为
科学上网:翻墙、VPN、Shadowsocks,政策风险,会被关站!
不懂提问:提问太随意,需要再做一遍《提问的智慧》测验
随意提问:提问没有发布在社区问答分类下
排版混乱:没有合理使用 Markdown 编写文章,未使用代码高亮
内容结构混乱:逻辑不清晰,内容混乱,难以阅读
标题随意:标题党、标题不释义
尊重版权:分享付费课程、破解软件(付费),侵犯作者劳动成果
其他理由:请补充说明
举报
取消