介绍
对于应用程序运行的环境来说,不同的环境有不同的配置通常是很有用的。Laravel 利用 Vance Lucas 的 PHP 库 DotEnv 使得此项功能的实现变得非常简单。当应用程序收到请求时,.env 文件中列出的所有变量将被加载到 PHP 的超级全局变量 $_ENV 中。
使用
你可以使用 env 函数检索这些变量的值。事实上,如果你查看 Laravel 的配置文件,你就能注意到有数个选项已经使用了这个函数:
php
'debug' => env('APP_DEBUG', false),
传递给 env 函数的第二个值是「默认值」。如果给定的键不存在环境变量,则会使用该值。
使用分析
我们可以先看一下助手函数 env
php
if (! function_exists('env')) {
/**
* Gets the value of an environment variable.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
function env($key, $default = null)
{
return Env::get($key, $default);
}
}
ENV::get 最终追踪到 EnvConstAdapter get
php
/**
* Get an environment variable, if it exists.
*
* @param string $name
*
* @return \PhpOption\Option
*/
public function get($name)
{
if (array_key_exists($name, $_ENV)) {
return Some::create($_ENV[$name]);
}
return None::create();
}
读取_ENV内容,_ENV是 通过环境提供给脚本的变量
php
/**
* @xglobal $_ENV array
*
* Variables provided to the script via the environment.
* Analogous to the old $HTTP_ENV_VARS array (which is still available, but deprecated).
*
* <p><a href="https://secure.php.net/manual/en/reserved.variables.php">
* https://secure.php.net/manual/en/reserved.variables.php</a>
*/
$_ENV = array();
写入$_ENV
bootstrap/app.php中
php
try {
(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(dirname(__DIR__)))->bootstrap();
} catch (Dotenv\Exception\InvalidPathException $e) {
//
}
Laravel\Lumen\Bootstrap\LoadEnvironmentVariables 中
php
<?php
namespace Laravel\Lumen\Bootstrap;
use Dotenv\Dotenv;
use Dotenv\Exception\InvalidFileException;
use Illuminate\Support\Env;
use Symfony\Component\Console\Output\ConsoleOutput;
class LoadEnvironmentVariables
{
/**
* The directory containing the environment file.
*
* @var string
*/
protected $filePath;
/**
* The name of the environment file.
*
* @var string|null
*/
protected $fileName;
/**
* Create a new loads environment variables instance.
*
* @param string $path
* @param string|null $name
* @return void
*/
public function __construct($path, $name = null)
{
$this->filePath = $path;
$this->fileName = $name;
}
/**
* Setup the environment variables.
*
* If no environment file exists, we continue silently.
*
* @return void
*/
public function bootstrap()
{
try {
$this->createDotenv()->safeLoad();
} catch (InvalidFileException $e) {
$this->writeErrorAndDie([
'The environment file is invalid!',
$e->getMessage(),
]);
}
}
/**
* Create a Dotenv instance.
*
* @return \Dotenv\Dotenv
*/
protected function createDotenv()
{
return Dotenv::create(
$this->filePath,
$this->fileName,
Env::getFactory()
);
}
/**
* Write the error information to the screen and exit.
*
* @param string[] $errors
* @return void
*/
protected function writeErrorAndDie(array $errors)
{
$output = (new ConsoleOutput)->getErrorOutput();
foreach ($errors as $error) {
$output->writeln($error);
}
die(1);
}
}
我们可以看到 bootstrap方法是创建Dotenv实例,并且调用Dotenv实例的safeload方法,Dotenv::create参数的含义
$this->filePath, #env所在目录
$this->fileName, #env名称,默认 .env
Env::getFactory() #laravel env相关的适配器工厂
由此我们可以自定义.env的位置和名称
safeload方法
php
/**
* Load environment file in given directory.
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function load()
{
return $this->loadData();
}
/**
* Load environment file in given directory, silently failing if it doesn't exist.
*
* @throws \Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function safeLoad()
{
try {
return $this->loadData();
} catch (InvalidPathException $e) {
// suppressing exception
return [];
}
}
/**
* Load environment file in given directory.
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
public function overload()
{
return $this->loadData(true);
}
/**
* Actually load the data.
*
* @param bool $overload
*
* @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
*
* @return array<string|null>
*/
protected function loadData($overload = false)
{
return $this->loader->setImmutable(!$overload)->load();
}
根据代码分析,safeLoad 中使用了 try {} catuch {} 捕获了异常,不会因为地址错误而报错,同时加载loadData,这里默认使用了loadData = true, 影响的Dotenv 创建的 DotenvVariables(array $adapters, $immutable)实例属性 $immutable值。我们通过追踪load方法,最终可以找到该方法:
php
/**
* Set an environment variable.
*
* @param string $name
* @param string|null $value
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function set($name, $value = null)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Expected name to be a string.');
}
// Don't overwrite existing environment variables if we're immutable
// Ruby's dotenv does this with `ENV[key] ||= value`.
if ($this->isImmutable() && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) {
return;
}
$this->setInternal($name, $value);
$this->loaded->set($name, '');
}
此时我们明白,如果$immutable = true的话,如果之前环境变量有了该值,后面的配置文件无法进行更改环境变量的值,如果没有该值进行添加