laravel .env环境变量原理

介绍

对于应用程序运行的环境来说,不同的环境有不同的配置通常是很有用的。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的话,如果之前环境变量有了该值,后面的配置文件无法进行更改环境变量的值,如果没有该值进行添加

相关推荐
机器之心34 分钟前
全球十亿级轨迹点驱动,首个轨迹基础大模型来了
人工智能·后端
黑客Ela39 分钟前
网络安全问题概述
安全·web安全·php
Wh1teR0se42 分钟前
详解php://filter--理论
web安全·php
潜洋2 小时前
Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
java·spring boot·后端
St_Ludwig2 小时前
C语言 蓝桥杯某例题解决方案(查找完数)
c语言·c++·后端·算法·游戏·蓝桥杯
vener_3 小时前
LuckySheet协同编辑后端示例(Django+Channel,Websocket通信)
javascript·后端·python·websocket·django·luckysheet
计算机毕设孵化场3 小时前
计算机毕设-基于springboot的多彩吉安红色旅游网站的设计与实现(附源码+lw+ppt+开题报告)
vue.js·spring boot·后端·计算机外设·课程设计·计算机毕设论文·多彩吉安红色旅游网站
爪哇学长3 小时前
解锁API的无限潜力:RESTful、SOAP、GraphQL和Webhooks的应用前景
java·开发语言·后端·restful·graphql
战神刘玉栋3 小时前
《SpringBoot、Vue 组装exe与套壳保姆级教学》
vue.js·spring boot·后端
码到成功>_<5 小时前
Spring Boot实现License生成和校验
数据库·spring boot·后端