Laravel-env使用注意事项

Docker部署laravel使用redis出现6379端口被重写原因

lumen 安装的 phpdotenv 库会优先默认选择系统中的环境变量。所以会重写覆盖了.env文件的redis_port连接信息,最终变tcp://:tcp://redis:6379

解决方法一:

1
2
3
// 避开系统默认变量名,例如:
NN_REDIS_HOST=127.0.0.1
NN_REDIS_PORT=6379

解决方法二:

1
2
3
在bootstrap/app.php文件中
将 (new Dotenv\Dotenv(__DIR__.'/../'))->load();
改为 (new Dotenv\Dotenv(__DIR__.'/../'))->overload();

案例分析

让我们看看这段代码,bootstrap/app.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
示例一:
try {
putenv("REDIS_HOST=tcp://redis:6379");
$res = (new Dotenv\Dotenv(__DIR__.'/../'))->load();
echo env("REDIS_HOST", '127.0.0.1');
} catch (Dotenv\Exception\InvalidPathException $e) {
//
}
本例输出:tcp://redis:6379
原因:Dotenv的load方法默认以系统变量为最高优先级

示例二:
try {
putenv("REDIS_HOST=tcp://redis:6379");
$res = (new Dotenv\Dotenv(__DIR__.'/../'))->overload();
echo env("REDIS_HOST", '127.0.0.1');
} catch (Dotenv\Exception\InvalidPathException $e) {
//
}
当且仅当.env文件有定义REDIS_HOST=1.1.1.1时:
本例输出:1.1.1.1
若不然:
本例输出:tcp://redis:6379

原因:Dotenv的overload方法默认以开发者变量为最高优先级

那么为什么当点.env文件未定义REDIS_HOST时env()函数的默认值没有生效呢?
这是因为没有开发者变量时,会采用系统变量,getenv()函数是有返回值的
所以当系统变量或开发者变量其中一个存在时,env()函数的默认值就不会生效

注意

php的 `getenv()`和`putenv()` 函数是非线程安全的
例如在windows或者apache环境下,可能出现线程重入,造成几个WEB应用"串值"的情况

避免在app/config/*目录外使用env函数

在 Laravel 中,如果执行 php aritisan config:cache 命令 (生产环境为了提高配置加载速度),Laravel 将会把 app/config 目录下的所有配置文件 “编译” 整合成一个缓存配置文件到 bootstrap/cache/config.php,每个配置文件都可以通过 env 函数读取环境变量,这里是可以读取的。但是一旦有了这个缓存配置文件,在其他地方使用 env 函数是读取不到环境变量的,所以返回 null.

让我们看看这段代码,Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php line 25:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function bootstrap(Application $app)
{
if ($app->configurationIsCached()) {
return;
}

$this->checkForSpecificEnvironmentFile($app);

try {
$this->createDotenv($app)->safeLoad();
} catch (InvalidFileException $e) {
$this->writeErrorAndDie($e);
}
}

这个方法在框架启动后就会运行,这段代码说明了如果存在缓存配置文件,就不会去设置环境变量了,配置都读缓存配置文件,而不会再读环境变量了。

因此,在配置文件即 app/config 目录下的其他地方,读取配置不要使用 env 函数去读环境变量,这样你一旦执行 php artisan config:cache 之后,env 函数就不起作用了。所有要用到的环境变量,在 app/config 目录的配置文件中通过 env 读取,其他地方要用到环境变量的都统一读配置文件而不是使用 env 函数读取。


修改env配置不生效可能原因

在 Laravel 项目中,如果执行了 php artisan config:cache 命令把配置文件缓存起来后

需要执行 php artisan config:clear 清除配置缓存后才会读取新的配置

或者再次执行 php artisan config:cache 重新生成缓存文件


.env 配置文件适用范围

.env 文件主要的作用是存储环境变量,也就是会随着环境变化的东西,比如数据库的用户名、密码、缓存驱动、时区,还有静态文件的存储路径之类的;
因为这些信息应该是和环境绑定的,不应该随代码的更新而变化,所以一般不会把 .env 文件放到版本控制中;

除了和环境绑定的环境变量,有时候一些安全系数比较高,不希望纳入版本控制的信息也会放进 .env 文件,比如第三方API的secret之类的;

不太适用的内容

严格来说,传统的配置信息,比如上传文件的尺寸限制,或者一些算法的阈值之类的,其实不适合放到 .env 文件中,因为这些配置项是要和代码一同更新,且所有环境下应该都是一致的;
所以这些配置项还是放到可以被版本控制工具管理的配置文件中更合适——说是这么说……但我们在使用 lumen 的时候也经常把这些配置项放进 .env (这大概不是什么好习惯),毕竟如果这些配置项很少的话,单独建一个配置文件也有些不值的感觉……


.env 中的基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// .env 中的数据按行划分, 每条数据占一行,数据之间可以有任意多的空行
// 每条数据的核心是一个等号,等号左侧是 key,右侧是 value
KEY1=value1

// 在 key 的前后和 value 的前后都可以添加任意多的空格,读取时会自动去除前后空格
KEY = value

// 如果 key 或者 value 中包含空格,就需要在两端加上双引号
"TEST KEY" = "test value"

// 如果需要添加注释,可以使用#
#测试单行注释
KEY=value #测试行末注释

// 如果需要嵌套变量的话,也可以直接在 .env 中写
BASE_DIR="/var/webroot/project-root"
CACHE_DIR="${BASE_DIR}/cache"
TMP_DIR="${BASE_DIR}/tmp"

评论