原始碼小記 Application 初始化 setBasePath

php_yt發表於2022-06-04

laravel version : 6.20.44
IDE : VsCode
程式碼追蹤元件 : "barryvdh/laravel-ide-helper": "2.8"

這篇分析圖片中的這一行程式碼

原始碼小記 容器初始化 setBasePath

__construct 接收一個引數 $basePath ⌈應用的根路徑⌉,相對於 ~/bootstrap/app.php 則是 dirname(__DIR__)

 __DIR__: D:\MyCode\study\laravel\laravel6\bootstrap
 dirname(__DIR__): D:\MyCode\study\laravel\laravel6

回到 __construct 方法,第一行呼叫 $this->setBasePath($basePath);,為了方便檢視,我把這行程式碼有關的程式碼單獨分離了出來放進偽 class 檔案裡

<?php
class Path
{
  protected $basePath; //根路徑 D:\MyCode\study\laravel\laravel6
  protected $appPath; // The custom application path defined by the developer.
  protected $databasePath; // The custom database path defined by the developer.
  protected $storagePath; // The custom storage path defined by the developer.
  protected $environmentPath;// The custom environment path defined by the developer.

  public function __construct($basePath = null)
  {
    if ($basePath) {
      $this->setBasePath($basePath);
    }
  }

  public function setBasePath($basePath)
  {
    $this->basePath = rtrim($basePath, '\/');

    $this->bindPathsInContainer();

    return $this;
  }

  protected function bindPathsInContainer()
  {
    $this->instance('path', $this->path());
    $this->instance('path.base', $this->basePath());
    $this->instance('path.lang', $this->langPath());
    $this->instance('path.config', $this->configPath());
    $this->instance('path.public', $this->publicPath());
    $this->instance('path.storage', $this->storagePath());
    $this->instance('path.database', $this->databasePath());
    $this->instance('path.resources', $this->resourcePath());
    $this->instance('path.bootstrap', $this->bootstrapPath());
  }

  public function path($path = '')
  {
    $appPath = $this->appPath ?: $this->basePath . DIRECTORY_SEPARATOR . 'app';

    return $appPath . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }
  public function basePath($path = '')
  {
    return $this->basePath . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }
  public function langPath()
  {
    return $this->resourcePath() . DIRECTORY_SEPARATOR . 'lang';
  }
  public function configPath($path = '')
  {
    return $this->basePath . DIRECTORY_SEPARATOR . 'config' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }
  public function publicPath()
  {
    return $this->basePath . DIRECTORY_SEPARATOR . 'public';
  }
  public function storagePath()
  {
    return $this->storagePath ?: $this->basePath . DIRECTORY_SEPARATOR . 'storage';
  }
  public function databasePath($path = '')
  {
    return ($this->databasePath ?: $this->basePath . DIRECTORY_SEPARATOR . 'database') . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }
  public function resourcePath($path = '')
  {
    return $this->basePath . DIRECTORY_SEPARATOR . 'resources' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }
  public function bootstrapPath($path = '')
  {
    return $this->basePath . DIRECTORY_SEPARATOR . 'bootstrap' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
  }


  public function useAppPath($path)
  {
    $this->appPath = $path;

    $this->instance('path', $path);

    return $this;
  }
  public function useStoragePath($path)
  {
    $this->storagePath = $path;

    $this->instance('path.storage', $path);

    return $this;
  }
  public function useDatabasePath($path)
  {
    $this->databasePath = $path;

    $this->instance('path.database', $path);

    return $this;
  }
  public function useEnvironmentPath($path)
  {
    $this->environmentPath = $path;

    return $this;
  }
}

分析

1. 定義了

$basePath
$appPath
$databasePath
$storagePath
$environmentPath 五個屬性

思考:除了 $basePath,為什麼只定義這幾個目錄的屬性,而 resources,config 路徑卻沒有定義屬性?我們發現屬性的註解寫著 The custom,說明這幾個目錄路徑是允許自定義的。

2. 定義了

path($path = '')
basePath($path = '')
langPath()
configPath($path = '')
publicPath()
storagePath()
databasePath($path = '')
resourcePath($path = '')
bootstrapPath($path = '')
方法

一般情況下,在 $basePath 基礎上拼接成路徑,而允許自定義的屬性是這樣獲取的:

原始碼小記 Application 初始化 setBasePath

有的方法接收 $path='' 引數,有的卻沒有,不太理解,感覺沒什麼區別,以至於助手函式 helpers 中對是否接收 $path='' 引數的方法呼叫都不同:
$path='' 引數的:

if (! function_exists('database_path')) {

    function database_path($path = '')
    {
        return app()->databasePath($path);
    }
}

沒有 $path='' 引數的:

if (! function_exists('public_path')) {

    function public_path($path = '')
    {
        return app()->make('path.public').($path ? DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR) : $path);
    }
}
if (! function_exists('storage_path')) {

    function storage_path($path = '')
    {
        return app('path.storage').($path ? DIRECTORY_SEPARATOR.$path : $path);
    }
}

有點意思,什麼寫法都有了

3. 將路徑透過 instance($abstract, $instance) 放進 $instances 屬性,列印 $instances 屬性:

array:9 [
  "path" => "D:\MyCode\study\laravel\laravel6\app" //custom
  "path.base" => "D:\MyCode\study\laravel\laravel6"
  "path.lang" => "D:\MyCode\study\laravel\laravel6\resources\lang"
  "path.config" => "D:\MyCode\study\laravel\laravel6\config"
  "path.public" => "D:\MyCode\study\laravel\laravel6\public"
  "path.storage" => "D:\MyCode\study\laravel\laravel6\storage" //custom
  "path.database" => "D:\MyCode\study\laravel\laravel6\database" //custom
  "path.resources" => "D:\MyCode\study\laravel\laravel6\resources"
  "path.bootstrap" => "D:\MyCode\study\laravel\laravel6\bootstrap"
];

4. 定義了

useAppPath($path),
useStoragePath($path),
useDatabasePath($path),
useEnvironmentPath($path),

這四個方法也是對應四個可自定義的屬性,在論壇中搜尋 useAppPath 發現這篇文章
詳解 packagit 用了什麼黑魔法,並可完全替換 artisan 命令

本作品採用《CC 協議》,轉載必須註明作者和本文連結
welcome come back

相關文章