搜尋
首頁php框架LaravelLaravel框架下ENV的載入與讀取的介紹

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

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

這篇文章帶給大家的內容是關於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中文網其他相關文章!

陳述
本文轉載於:segmentfault思否。如有侵權,請聯絡admin@php.cn刪除
Laravel(PHP)與Python:不同的用例和應用Laravel(PHP)與Python:不同的用例和應用Apr 18, 2025 am 12:16 AM

選擇Laravel或Python取決於項目需求:1)若需快速開發Web應用並使用ORM和認證系統,選Laravel;2)若涉及數據分析、機器學習或科學計算,選Python。

Laravel和Python:找到合適的工具Laravel和Python:找到合適的工具Apr 18, 2025 am 12:14 AM

Laravel适合快速构建Web应用,Python适用于需要灵活性和多功能性的项目。1)Laravel提供丰富功能如ORM和路由,适合PHP生态系统。2)Python以简洁语法和强大库生态系统著称,适用于Web开发和数据科学等领域。

Laravel和PHP:創建動態網站Laravel和PHP:創建動態網站Apr 18, 2025 am 12:12 AM

使用Laravel和PHP可以高效且有趣地創建動態網站。 1)Laravel遵循MVC架構,Blade模板引擎簡化HTML編寫。 2)路由系統和請求處理機制使URL定義和用戶輸入處理變得簡單。 3)EloquentORM簡化數據庫操作。 4)通過博客系統示例展示了數據庫遷移、CRUD操作和Blade模板的使用。 5)Laravel提供了強大的用戶認證和授權功能。 6)調試技巧包括使用日誌系統和Artisan工具。 7)性能優化建議包括惰性加載和緩存。

拉維爾(Laravel)和完整的堆棧:前後一起拉維爾(Laravel)和完整的堆棧:前後一起Apr 18, 2025 am 12:07 AM

Laravel通過Blade模板引擎、EloquentORM、Artisan工具和LaravelMix實現全棧開發:1.Blade簡化前端開發;2.Eloquent簡化數據庫操作;3.Artisan提高開發效率;4.LaravelMix管理前端資源。

Laravel:現代網絡開發的框架Laravel:現代網絡開發的框架Apr 18, 2025 am 12:05 AM

Laravel是一個基於PHP的現代化框架,遵循MVC架構模式,提供了豐富的工具和功能,簡化了Web開發過程。 1)它包含EloquentORM用於數據庫交互,2)Artisan命令行接口用於快速生成代碼,3)Blade模板引擎用於高效的視圖開發,4)強大的路由系統用於定義URL結構,5)認證系統用於用戶管理,6)事件監聽和廣播用於實時功能,7)緩存和隊列系統用於性能優化,使得構建和維護現代Web應用變得更加容易和高效。

Laravel(PHP)與Python:權衡優點和缺點Laravel(PHP)與Python:權衡優點和缺點Apr 17, 2025 am 12:18 AM

Laravel适合快速构建Web应用,而Python适用于更广泛的应用场景。1.Laravel提供EloquentORM、Blade模板引擎和Artisan工具,简化Web开发。2.Python以动态类型、丰富的标准库和第三方生态系统著称,适用于Web开发、数据科学等领域。

Laravel vs. Python:比較框架和圖書館Laravel vs. Python:比較框架和圖書館Apr 17, 2025 am 12:16 AM

Laravel和Python各有優勢:Laravel適合快速構建功能豐富的Web應用,Python在數據科學和通用編程領域表現出色。 1.Laravel提供EloquentORM和Blade模板引擎,適合構建現代Web應用。 2.Python擁有豐富的標準庫和第三方庫,Django和Flask框架滿足不同開發需求。

Laravel的目的:構建強大而優雅的Web應用程序Laravel的目的:構建強大而優雅的Web應用程序Apr 17, 2025 am 12:13 AM

Laravel值得選擇,因為它能使代碼結構清晰,開發過程更具藝術性。 1)Laravel基於PHP,遵循MVC架構,簡化Web開發。 2)其核心功能如EloquentORM、Artisan工具和Blade模板增強了開發的優雅與健壯性。 3)通過路由、控制器、模型和視圖,開發者能高效構建應用。 4)隊列和事件監聽等高級功能進一步提升應用性能。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

記事本++7.3.1

記事本++7.3.1

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

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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