首頁 php框架 Laravel Laravel框架下ENV的載入與讀取的介紹

Laravel框架下ENV的載入與讀取的介紹

Oct 22, 2018 pm 02:17 PM
laravel php 原始碼分析

這篇文章帶給大家的內容是關於Laravel框架下ENV的加載和讀取的介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

Laravel在啟動時會載入專案中的.env檔。對於應用程式運行的環境來說,不同的環境有不同的配置通常是很有用的。例如,你可能希望在本地使用測試的Mysql資料庫而在上線後希望專案能夠自動切換到生產Mysql資料庫。本文將會詳細介紹 env 檔案的使用與原始碼的分析。

Env檔案的使用

多環境env的設定

#專案中env檔案的數量往往是跟專案的環境數量相同,假如一個專案有開發、測試、生產三套環境那麼在專案中應該有三個.env.dev、.env.test、.env.prod三個環境設定檔與環境相對應。三個檔案中的配置項目應該完全一樣,而具體配置的值應該根據每個環境的需要來設定。

接下來就是讓專案能夠根據環境載入不同的env檔案了。具體有三種方法,可以依照使用習慣來選擇使用:

在環境的nginx設定檔裡設定APP_ENV環境變數fastcgi_param APP_ENV dev;

設定伺服器上執行PHP的使用者的環境變量,例如在www用戶的/home/www/.bashrc中加入export APP_ENV dev

在部署專案的持續整合任務或部署腳本裡執行cp .env.dev .env

針對前兩種方法,Laravel會根據env('APP_ENV')載入到的變數值去載入對應的檔案.env.dev、.env.test這些。具體在後面原始碼裡會說,第三種比較好理解就是在部署專案時將環境的設定檔覆蓋到.env檔裡這樣就不需要在環境的系統和nginx裡做額外的設定了。

自訂env檔案的路徑與檔案名稱

env檔案預設放在專案的根目錄中,laravel 為使用者提供了自訂ENV 檔案路徑或文件名的函數,

例如,若想要自訂env 路徑,可以在bootstrap 資料夾中app.php 中使用Application實例的useEnvironmentPath方法:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

$app->useEnvironmentPath('/customer/path')
登入後複製

#若想要自訂env檔案名稱,就可以在bootstrap 資料夾中app.php 中使用Application實例的loadEnvironmentFrom方法:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

$app->loadEnvironmentFrom('customer.env')
登入後複製

Laravel 載入ENV配置

#Laravel載入ENV的是在在框架處理請求之前,bootstrap過程中的LoadEnvironmentVariables階段中完成的。

我們來看看\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables的原始碼來分析下Laravel是怎麼載入env中的配置的。

<?php
namespace Illuminate\Foundation\Bootstrap;
use Dotenv\Dotenv;
use Dotenv\Exception\InvalidPathException;
use Symfony\Component\Console\Input\ArgvInput;
use Illuminate\Contracts\Foundation\Application;
class LoadEnvironmentVariables
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }

        $this->checkForSpecificEnvironmentFile($app);

        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
        } catch (InvalidPathException $e) {
            //
        }
    }

    /**
     * Detect if a custom environment file matching the APP_ENV exists.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    protected function checkForSpecificEnvironmentFile($app)
    {
        if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
            if ($this->setEnvironmentFilePath(
                $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
            )) {
                return;
            }
        }

        if (! env('APP_ENV')) {
            return;
        }

        $this->setEnvironmentFilePath(
            $app, $app->environmentFile().'.'.env('APP_ENV')
        );
    }

    /**
     * Load a custom environment file.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  string  $file
     * @return bool
     */
    protected function setEnvironmentFilePath($app, $file)
    {
        if (file_exists($app->environmentPath().'/'.$file)) {
            $app->loadEnvironmentFrom($file);

            return true;
        }

        return false;
    }
}
登入後複製

在他的啟動方法bootstrap中,Laravel會檢查配置是否緩存過以及判斷應該應用那個env文件,針對上面說的根據環境加載配置文件的三種方法中的頭兩種,因為系統或nginx環境變數中設定了APP_ENV,所以Laravel會在checkForSpecificEnvironmentFile方法裡根據APP_ENV的值設定正確的設定檔的具體路徑, 例如.env.dev或.env.test,而針對第三中情況則是預設的.env, 具體可以參考下面的checkForSpecificEnvironmentFile還有相關的Application裡的兩個方法的源碼:

protected function checkForSpecificEnvironmentFile($app)
{
    if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
        if ($this->setEnvironmentFilePath(
            $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
        )) {
            return;
        }
    }

    if (! env('APP_ENV')) {
        return;
    }

    $this->setEnvironmentFilePath(
        $app, $app->environmentFile().'.'.env('APP_ENV')
    );
}

namespace Illuminate\Foundation;
class Application ....
{

    public function environmentPath()
    {
        return $this->environmentPath ?: $this->basePath;
    }
    
    public function environmentFile()
    {
        return $this->environmentFile ?: '.env';
    }
}
登入後複製

判斷好後要讀取的配置文件的路徑後,接下來就是加載env裡的配置了。

(new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
登入後複製

Laravel使用的是Dotenv的PHP版本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();
    }
}
登入後複製

它依賴/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;
    }
}
登入後複製

Loader讀取配置時readLinesFromFile函數會用file函數將配置從文件中一行行地讀取到數組中去,然後排除以#開頭的註釋,針對內容中包含=的行去調用setEnvironmentVariable方法去把文件行中的環境變量配置到項目中去:

namespace Dotenv;
class Loader
{
    public function setEnvironmentVariable($name, $value = null)
    {
        list($name, $value) = $this->normaliseEnvironmentVariable($name, $value);

        $this->variableNames[] = $name;

        // Don't overwrite existing environment variables if we're immutable
        // Ruby's dotenv does this with `ENV[key] ||= value`.
        if ($this->immutable && $this->getEnvironmentVariable($name) !== null) {
            return;
        }

        // If PHP is running as an Apache module and an existing
        // Apache environment variable exists, overwrite it
        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;
    }
    
    public function getEnvironmentVariable($name)
    {
        switch (true) {
            case array_key_exists($name, $_ENV):
                return $_ENV[$name];
            case array_key_exists($name, $_SERVER):
                return $_SERVER[$name];
            default:
                $value = getenv($name);
                return $value === false ? null : $value; // switch getenv default to null
        }
    }
}
登入後複製

<span style="font-family: 微软雅黑, Microsoft YaHei;">Dotenv實例化Loader的時候把Loader物件的$immutable屬性設定成了false,Loader設定變數的時候如果透過getEnvironmentVariable方法讀取到了變數值,那麼就會跳過該環境變數的設定。所以Dotenv預設不會覆寫已經存在的環境變量,這個很關鍵,比如說在docker的容器編排檔案裡,我們會給PHP應用容器設定關於Mysql容器的兩個環境變數</span><br>

    environment:
      - "DB_PORT=3306"
      - "DB_HOST=database"
登入後複製

這樣在容器裡設定好環境變數後,即使env檔案裡的DB_HOST為homestead用env函數讀取出來的也還是容器裡之前設定的DB_HOST環境變數的值database(docker中容器連結預設使用服務名稱,在編排檔案中我把mysql容器的服務名稱設定成了database, 所以php容器要透過database這個host來連接mysql容器)。因為用我們在持續集成中做自動化測試的時候通常都是在容器裡進行測試,所以Dotenv不會覆蓋已存在環境變量這個行為就相當重要這樣我就可以只設置容器裡環境變量的值完成測試而不用更改專案裡的env文件,等到測試完成後直接去將專案部署到環境上就可以了。

如果檢查環境變數不存在那麼接著Dotenv就會把環境變數透過PHP內建函數putenv設定到環境中去,同時也會儲存到$_ENV和$_SERVER這兩個全域變數中。

在專案中讀取env配置

在Laravel應用程式中可以使用env()函數去讀取環境變數的值,例如取得資料庫的HOST:

env('DB_HOST`, 'localhost');
登入後複製

傳遞給env 函數的第二個值是「預設值」。如果給定的鍵不存在環境變量,則會使用該值。

我們來看看env函數的原始碼:

function env($key, $default = null)
{
    $value = getenv($key);

    if ($value === false) {
        return value($default);
    }

    switch (strtolower($value)) {
        case 'true':
        case '(true)':
            return true;
        case 'false':
        case '(false)':
            return false;
        case 'empty':
        case '(empty)':
            return '';
        case 'null':
        case '(null)':
            return;
    }

    if (strlen($value) > 1 && Str::startsWith($value, '"') && Str::endsWith($value, '"')) {
        return substr($value, 1, -1);
    }

    return $value;
}
登入後複製

它直接透過PHP內建函數getenv讀取環境變數。

我們看到了在載入配置和讀取配置的時候,使用了putenv和getenv兩個函數。 putenv設定的環境變數只在請求期間存活,請求結束後會恢復環境之前的設定。因為如果php.ini中的variables_order配置項目變成GPCS不包含E的話,那麼php程式中是無法透過$_ENV讀取環境變數的,所以使用putenv動態地設定環境變數讓開發人員不用去關注伺服器上的配置。而且在伺服器上給運行用戶配置的環境變量會共享給用戶啟動的所有進程,這就不能很好的保護比如DB_PASSWORD、API_KEY這種私密的環境變量,所以這種配置用putenv設置能更好的保護這些配置訊息,getenv方法能獲取到系統的環境變數和putenv動態設定的環境變數。

以上是Laravel框架下ENV的載入與讀取的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1274
29
C# 教程
1256
24
如果session_start()被多次調用會發生什麼? 如果session_start()被多次調用會發生什麼? Apr 25, 2025 am 12:06 AM

多次調用session_start()會導致警告信息和可能的數據覆蓋。 1)PHP會發出警告,提示session已啟動。 2)可能導致session數據意外覆蓋。 3)使用session_status()檢查session狀態,避免重複調用。

作曲家:通過AI的幫助開發PHP 作曲家:通過AI的幫助開發PHP Apr 29, 2025 am 12:27 AM

AI可以幫助優化Composer的使用,具體方法包括:1.依賴管理優化:AI分析依賴關係,建議最佳版本組合,減少衝突。 2.自動化代碼生成:AI生成符合最佳實踐的composer.json文件。 3.代碼質量提升:AI檢測潛在問題,提供優化建議,提高代碼質量。這些方法通過機器學習和自然語言處理技術實現,幫助開發者提高效率和代碼質量。

session_start()函數的意義是什麼? session_start()函數的意義是什麼? May 03, 2025 am 12:18 AM

session_start()iscucialinphpformanagingusersessions.1)ItInitiateSanewsessionifnoneexists,2)resumesanexistingsessions,and3)setsasesessionCookieforContinuityActinuityAccontinuityAcconActInityAcconActInityAcconAccRequests,EnablingApplicationsApplicationsLikeUseAppericationLikeUseAthenticationalticationaltication and PersersonalizedContentent。

php框架laravel和yii區別是什麼 php框架laravel和yii區別是什麼 Apr 30, 2025 pm 02:24 PM

Laravel和Yii的主要區別在於設計理念、功能特性和使用場景。 1.Laravel注重開發的簡潔和愉悅,提供豐富的功能如EloquentORM和Artisan工具,適合快速開發和初學者。 2.Yii強調性能和效率,適用於高負載應用,提供高效的ActiveRecord和緩存系統,但學習曲線較陡。

哪些數據庫版本與最新的Laravel兼容? 哪些數據庫版本與最新的Laravel兼容? Apr 25, 2025 am 12:25 AM

最新版本的Laravel10與MySQL5.7及以上、PostgreSQL9.6及以上、SQLite3.8.8及以上、SQLServer2017及以上兼容。這些版本選擇是因為它們支持Laravel的ORM功能,如MySQL5.7的JSON數據類型,提升了查詢和存儲效率。

H5:HTML5的關鍵改進 H5:HTML5的關鍵改進 Apr 28, 2025 am 12:26 AM

HTML5帶來了五個關鍵改進:1.語義化標籤提升了代碼清晰度和SEO效果;2.多媒體支持簡化了視頻和音頻嵌入;3.表單增強簡化了驗證;4.離線與本地存儲提高了用戶體驗;5.畫布與圖形功能增強了網頁的可視化效果。

Laravel 最佳擴展包推薦:2024 年必備工具 Laravel 最佳擴展包推薦:2024 年必備工具 Apr 30, 2025 pm 02:18 PM

2024年必備的Laravel擴展包包括:1.LaravelDebugbar,用於監控和調試代碼;2.LaravelTelescope,提供詳細的應用監控;3.LaravelHorizon,管理Redis隊列任務。這些擴展包能提升開發效率和應用性能。

如何使用MySQL的函數進行數據處理和計算 如何使用MySQL的函數進行數據處理和計算 Apr 29, 2025 pm 04:21 PM

MySQL函數可用於數據處理和計算。 1.基本用法包括字符串處理、日期計算和數學運算。 2.高級用法涉及結合多個函數實現複雜操作。 3.性能優化需避免在WHERE子句中使用函數,並使用GROUPBY和臨時表。

See all articles