Laravel源碼--Facade門面

文章簡單介紹了 Facade 門面,總結(jié)了其工作原理,并介紹了 Facade 的使用方法。

介紹

Facade 為應(yīng)用服務(wù)容器中綁定的類提供了一個“靜態(tài)”接口。Laravel 內(nèi)置了很多 Facade,幾乎可以用來訪問 Laravel 中所有的服務(wù)。Laravel 的 Facade 作為服務(wù)容器中底層類的“靜態(tài)代理”,相比于傳統(tǒng)靜態(tài)方法,F(xiàn)acade 提供了簡潔且豐富的語法同時,還帶來了更好的可測試性和擴展性。Laravel 的所有 Facade 都定義在 “Illuminate\Support\Facades”命名空間下,我們也可以自己定義新的 Facade。

Facade 加載原理

為了更好的理解 Facade 的工作原理,我們從以下幾個方面進行介紹:

  • Facade 配置文件
  • 加載 RegisterFacades 類
  • 注冊 Facade 服務(wù)
  • 解析 Facade 服務(wù)

Facade配置文件

Facade 的配置文件保存在 config/app.php 中,主要用來保存所有的 Facade 別名,也即是把 Facade 和別名的對應(yīng)關(guān)系存放在 config/app.php文件中的 aliases 數(shù)組里。aliases 數(shù)組的形式如下:


    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,

    ],

aliases 數(shù)組遵循(別名 => Facade 類)的數(shù)據(jù)格式,當接受一個 HTTP 請求時注冊 aliases 數(shù)組,但是并沒有實際的進行別名綁定,只是通過 spl_autoload_register() 函數(shù)進行了注冊。只有在遇到尚未發(fā)現(xiàn)的別名時,才去真正綁定別名,因此,別名綁定是“懶惰”加載,并不影響程序的性能。

加載 RegisterFacades 類

Facade 服務(wù)的注冊工作由“Illuminate\Foundation\Bootstrap\RegisterFacades”類完成,RegisterFacades 類是在啟動應(yīng)用程序的過程中加載的。因此,我們首先來看index.php文件

<?php
//public\index.php
/**
 * 記錄框架的啟動時間
 * microtime(get_as_float)函數(shù)返回當前Unix時間戳的微妙數(shù)
 * get_as_float為true時返回浮點數(shù),為false時返回字符串,默認為false
 */
define('LARAVEL_START', microtime(true));

/**
 * Composer的自動加載文件
 */
require __DIR__.'/../vendor/autoload.php';

/**
 * bootstrap文件里創(chuàng)建了一個Application實例
 */
$app = require_once __DIR__.'/../bootstrap/app.php';

/**
 * 通過container服務(wù)容器獲得一個kernel類的實例,(Illuminate\Contracts\Http\Kernel是一個接口,
 * 真正生成的實例是App\Http\Kernel類)
 */
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);


/**
 * laravel中所有功能服務(wù)的注冊加載
 * 通過調(diào)用kernel的handle方法,返回一個response
 * Illuminate\Http\Request::capture():通過全局$_SERVER數(shù)組構(gòu)造一個Http請求的語句
 */
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

//把response內(nèi)容發(fā)到瀏覽器
$response->send();

//執(zhí)行請求生命周期中的后續(xù)操作
$kernel->terminate($request, $response);

RegisterFacades 類的加載是在 $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ) 語句進行的。該語句主要用于 Laravel各個功能服務(wù)的注冊啟動。

$request = Illuminate\Http\Request::capture() 

該語句是 Laravel 通過全局 $_SERVER 數(shù)組構(gòu)造一個 HTTP 請求的語句,接下來會調(diào)用 HTTP 的內(nèi)核函數(shù) handle(),RegisterFacades 類的加載即是在內(nèi)核函數(shù) handle() 中進行。

//Illuminate\Foundation\Http\Kernel.php
    /**
     * Handle an incoming HTTP request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function handle($request)
    {
        try {
            //允許在表單中使用delete、put等類型的請求
            $request->enableHttpMethodParameterOverride();

            //將請求發(fā)給中間件、路由處理
            $response = $this->sendRequestThroughRouter($request);
        } catch (Exception $e) {
            $this->reportException($e);

            $response = $this->renderException($request, $e);
        } catch (Throwable $e) {
            $this->reportException($e = new FatalThrowableError($e));

            $response = $this->renderException($request, $e);
        }

        $this->app['events']->dispatch(
            new Events\RequestHandled($request, $response)
        );

        return $response;
    }

接下來,我們查看 sendRequestThroughRouter() 函數(shù)。

//Illuminate\Foundation\Http\Kernel.php
     /**
     * Send the given request through the middleware / router.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendRequestThroughRouter($request)
    {
        //設(shè)置request請求的對象實例
        $this->app->instance('request', $request);

        //清楚'request'對應(yīng)的服務(wù)對象實例
        Facade::clearResolvedInstance('request');

        /**
         * 依次執(zhí)行$bootstrappers中每一個bootstrapper的bootstrap()函數(shù),做了幾件準備事情:
         * 1. 配置加載 LoadConfiguration
         * 2.日志配置 ConfigureLogging
         * 3.異常處理 HandleException
         * 4.注冊Facades RegisterFacades
         * 5.注冊Providers RegisterProviders
         * 6.啟動Providers BootProviders
         */
        $this->bootstrap();

        return (new Pipeline($this->app))       //請求的分發(fā)
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
    }

函數(shù)首先在 Laravel 容器中設(shè)置了 request 請求的對象實例,并且清楚了 Facade 中 request 請求對應(yīng)的服務(wù)對象實例。接下來我們來看 bootstrap() 函數(shù)

//Illuminate\Foundation\Http\Kernel.php
     /**
     * Bootstrap the application for HTTP requests.
     * 啟動引導(dǎo)(reauests驅(qū)動)
     *
     * @return void
     */
    public function bootstrap()
    {
        //判斷引導(dǎo)是否已經(jīng)被啟動
        if (! $this->app->hasBeenBootstrapped()) {
            /**
             * 使用Application類的bootstrapWith()函數(shù)啟動引導(dǎo)
             * 參數(shù):bootstrapers數(shù)組。
             */
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }

     /**
     * The bootstrap classes for the application.
     * 引導(dǎo)類,起引導(dǎo)作用的類
     *
     * @var array
     */
    protected $bootstrappers = [
        //載入服務(wù)器環(huán)境變量(.env文件)
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        //載入配置信息(config目錄)
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        //配置異常處理
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        //注冊Facades
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        //注冊Providers
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        //啟動Providers
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];

bootstrap() 函數(shù)首先判斷引導(dǎo)類是否已經(jīng)啟動,如果沒有啟動,則啟動引導(dǎo)類。引導(dǎo)類數(shù)組包含 RegisterFacades 類。啟動引導(dǎo)類是調(diào)用“Illuminate\Foundation\Application”類中的 bootstrapWith() 函數(shù)。

//Illuminate\Foundation\Application
     /**
     * Run the given array of bootstrap classes.
     *
     * @param  array  $bootstrappers
     * @return void
     */
    public function bootstrapWith(array $bootstrappers)
    {
        $this->hasBeenBootstrapped = true;

        foreach ($bootstrappers as $bootstrapper) {
            /**
             * 告知將要啟動該bootstrapper
             * $this['events']:對應(yīng)綁定的類為 Dispatcher類(Illuminate\Events\Dispatcher)
             * [$this]:數(shù)組,只有一個Application類元素
             */
            $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);

            //解析每個 $bootstrapper,并調(diào)用他們自身的 bootstrap() 函數(shù)
            $this->make($bootstrapper)->bootstrap($this);

            $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
        }
    }

bootstrapWith() 函數(shù)中的 $this->make($bootstrapper)->bootstrap($this) 語句即是解析出 $bootstrappers 數(shù)組中的每個類,并調(diào)用相應(yīng)的 bootstrap() 函數(shù)。因此,RegisterFacades 類也即是在此時調(diào)用。

注冊 Facade 服務(wù)

下面我們來看 RegisterFacades 類。

//Illuminate\Foundation\Bootstrap\RegisterFacades.php
<?php

namespace Illuminate\Foundation\Bootstrap;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Facade;
use Illuminate\Foundation\PackageManifest;
use Illuminate\Contracts\Foundation\Application;

class RegisterFacades
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        //清除所有的門面對象服務(wù)實例
        Facade::clearResolvedInstances();

        //設(shè)置門面對象的Application實例
        Facade::setFacadeApplication($app);

        /**
         * 默認的別名配置是從 app 配置文件下的 aliases 讀取的,
         * PackageManifest 是 laravel 5.5 新增的 包自動發(fā)現(xiàn) 規(guī)則
         */
        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }
}

可以看出,RegisterFacades 類只有一個 bootstrap() 函數(shù),該函數(shù)主要完成以下功能:

  • 清楚所有 Facade 對象服務(wù)實例
  • 設(shè)置門面對象的 Application 實例
  • 通過 AliasLoader 類為所有的 Facade 注冊別名

接下來我們查看 AliasLoader 類如何注冊別名。

//llluminate\Foundation\AliasLoader.php
     /**
     * Get or create the singleton alias loader instance.
     * 獲取或創(chuàng)建 AliasLoader 單例實例。
     *
     * @param  array  $aliases
     * @return \Illuminate\Foundation\AliasLoader
     */
    public static function getInstance(array $aliases = [])
    {
        if (is_null(static::$instance)) {
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }

     /**
     * Register the loader on the auto-loader stack.
     * 將加載器注冊到自動加載中
     *
     * @return void
     */
    public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }

     /**
     * Prepend the load method to the auto-loader stack.
     * 設(shè)置自動加載方法
     *
     * @return void
     */
    protected function prependToLoaderStack()
    {
        // 把AliasLoader::load()放入自動加載函數(shù)隊列中,并置于隊列頭部
        spl_autoload_register([$this, 'load'], true, true);
    }

AliasLoader 類首先調(diào)用 getInstance() 函數(shù)獲得 AliasLoader 的單例實例,然后調(diào)用 register() 函數(shù)將 AliasLoader 類中的 load() 函數(shù)注冊到 SPL __autoload 函數(shù)隊列的頭部。

//llluminate\Foundation\AliasLoader.php
     /**
     * Load a class alias if it is registered.
     *
     * @param  string  $alias
     * @return bool|null
     */
    public function load($alias)
    {
        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);

            return true;
        }

        if (isset($this->aliases[$alias])) {
            //注冊別名
            return class_alias($this->aliases[$alias], $alias);
        }
    }

load() 函數(shù)的上半部分是 laravel5.4 版本新出的功能,叫做實時門面服務(wù)。下半部分是 class_alias() 函數(shù)利用別名映射數(shù)組將別名映射到真正的門面類中去。例如,我們使用別名類 Cache 時,程序會通過 AliasLoader 類的 load() 函數(shù)為“Illuminate\Support\Facades\Cache::class”類創(chuàng)建一個別名 Cache,所以我們在程序里使用別名 Cache 就是使用“Illuminate\Support\Facades\Cache”類。

解析 Facade 服務(wù)

以 Cache 為例,我們講一下 Facade 的使用。我們首先來看一下 Cache Facade 類。

<?php
//Illuminate\Support\Facades\Cache.php

class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     * 獲取組件注冊名稱
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'cache';
    }
}

該類內(nèi)部只有一個 getFacadeAccessor() 函數(shù),該方法的功能是獲取已經(jīng)注冊組件的名稱。其實每個門面類只是重寫了基類(Facade)的 getFacadeAccessor() 方法。

//Illuminate\Support\Facades\Facade.php
     /**
     * Handle dynamic, static calls to the object.
     * 動態(tài)綁定,將門面的靜態(tài)方法調(diào)用綁定到門面對應(yīng)的服務(wù)對象實例來執(zhí)行
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        //返回當前門面對應(yīng)的服務(wù)對象實例
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        //執(zhí)行服務(wù)對象實例相應(yīng)的方法
        return $instance->$method(...$args);
    }

當運行 Cache::get() 函數(shù)時,門面類 Cache 類里并沒有 get() 函數(shù),此時 PHP 會自動調(diào)用魔術(shù)函數(shù) __callStatic()。魔術(shù)函數(shù) __callStatic() 首先獲得 Facade 的服務(wù)對象實例,然后調(diào)用對象的 get() 函數(shù)。下面我們來看如何獲得 Facade 的對象實例。

//Illuminate\Support\Facades\Facade.php
     /**
     * Get the root object behind the facade.
     * 返回當前門面對應(yīng)服務(wù)對象的實例
     *
     * @return mixed
     */
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

   /**
     * Get the registered name of the component.
     * 獲取組件注冊名稱,子類重寫該函數(shù)
     *
     * @return string
     *
     * @throws \RuntimeException
     */
    protected static function getFacadeAccessor()
    {
        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
    }

     /**
     * Resolve the facade root instance from the container.
     * 創(chuàng)建并返回 $name 對應(yīng)的對象實例
     *
     * @param  string|object  $name
     * @return mixed
     */
    protected static function resolveFacadeInstance($name)
    {
        //如果是對象,則直接返回
        if (is_object($name)) {
            return $name;
        }

        //$resolvedInstance數(shù)組中 $name 對應(yīng)的對象實例是否存在,如果存在,直接返回
        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        /**
         * 具體的創(chuàng)建工作由Application類對象進行,所以$name需要在Application中進行過綁定
         */
        return static::$resolvedInstance[$name] = static::$app[$name];
    }

基類中的 getFacadeRoot() 函數(shù)首先調(diào)用了 getFacadeAccessor() 函數(shù),也即是 Cache 類重寫的 getFacadeAccessor() 函數(shù),如果調(diào)用的是基類的 getFacadeAccessor() 函數(shù)則報錯。然后調(diào)用 resolveFacadeInstance() 函數(shù)獲得“cache”對應(yīng)的服務(wù)實例。resolveFacadeInstance() 函數(shù)主要是從 Laravel 服務(wù)容器 static::$app[$name] 中解析出相應(yīng)的服務(wù)?!癱ache”服務(wù)是應(yīng)用程序初始化時,在類“Illuminate\Foundation\Bootstrap\RegisterProviders”中被注冊到容器中的。
因為在程序啟動時,將 Facade 的別名通過 RegisterFacades 類進行了加載注冊,所以可以直接使用別名 Cache 代替“Illuminate\Support\Facades\Cache”。
其實,Cache::get('key') 的寫法等價于以下寫法。

$value = $app->make('cache')->get('key');

建立 Facade

建立自己的 Facade,需要做以下幾方面的工作:

  • 創(chuàng)建自定義類(Facade 的實現(xiàn)類)
  • 創(chuàng)建 Facade 類
  • Facade 類別名設(shè)置
  • 創(chuàng)建 ServiceProvider
  • 加載 ServiceProvider

創(chuàng)建自定義類(Facade 的實現(xiàn)類)

我們現(xiàn)在 app\Facades 目錄下創(chuàng)建 PaymentGateway\Payment 類。

<?php
//app\Facades\\PaymentGateway\Payment.php

namespace App\Facades\PaymentGateway;

class Payment
{
    public function get(){
        return "Facade Test ...";
    }

}

創(chuàng)建 Facade 類

創(chuàng)建自定義的 Facade 類,該類繼承基類 Facade,并重寫基類的 getFacadeAccessor() 函數(shù)。

<?php
//app\Facades\\PaymentGateway\Facade\Payment.php

namespace App\Facades\PaymentGateway\Facade;
use Illuminate\Support\Facades\Facade;

class Payment extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'payment';
    }
}

Facade 類別名設(shè)置

我們可以為自定義的 Facade 類起個別名,只需要將別名和類的對應(yīng)關(guān)系添加到 config/app.php 配置文件中的 aliases 數(shù)組即可。

//config/app.php

  'aliases' => [
        ...
        'Payment' => App\Facades\PaymentGateway\Facade\Payment::class,
        ...
    ],

創(chuàng)建 ServiceProvider

在 app\Providers 文件夾下創(chuàng)建 PaymentServiceProvider,提供“payment”服務(wù)。

<?php
//app\Providers\PaymentServiceProvider.php

namespace App\Providers;

use App\Facades\PaymentGateway\Payment;
use Illuminate\Support\ServiceProvider;

class PaymentServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     * $defer為true,表示延遲加載此類
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('payment', function ($app) {
            return new Payment();
        });

    }

    /**
     * 設(shè)置了延遲啟動,需要重寫 providers 函數(shù)
     * 該方法返回provider中注冊的服務(wù)容器綁定別名
     */
    public function provides()
    {
        return ["payment"];
    }
}

其中,$defer 設(shè)置為 true,是為了提供延遲加載功能,provides() 函數(shù)也是為了輔助延遲加載功能而重寫的。register() 函數(shù)中的服務(wù)名“payment”應(yīng)該與 Facade 類中 getFacadeAccessor() 函數(shù)返回值保持一致。

加載 ServiceProvider

為了能加載我們創(chuàng)建的 PaymentServiceProvider,需要在 config/app.php 配置文件中 providers 數(shù)組內(nèi)添加 PaymentServiceProvider。

//config/app.php

    'providers' => [
        ...
        App\Providers\PaymentServiceProvider::class,
        ...
 ],

最后,使用如下代碼即可以調(diào)用 Facade 類。

$value = Payment::get();

總結(jié)

之所以能夠簡單的使用 Cache::get() 操作,是因為程序啟動時自動進行了別名注冊,使用 Cache 等價于“Illuminate\Support\Facades\Cache”。另外,程序在基類 Facade 中自動調(diào)用魔術(shù)函數(shù) __callStatic() 進行了動態(tài)綁定。

門面類列表

下面列出了每個 Facade 、對應(yīng)的底層類以及服務(wù)容器綁定鍵。

門面 Facade 類 Class 服務(wù)容器綁定
App Illuminate\Foundation\Application app
Artisan Illuminate\Console\Application artisan
Auth Illuminate\Auth\AuthManager auth
Auth (實例) Illuminate\Auth\Guard
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Bus Illuminate\Contracts\Bus\Dispatcher
Cache Illuminate\Cache\CacheManager cache
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB (實例) Illuminate\Database\Connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Hash Illuminate\Contracts\Hashing\Hasher hash
Input Illuminate\Http\Request request
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\Writer log
Mail Illuminate\Mail\Mailer mailer
Password Illuminate\Auth\Passwords\PasswordBroker auth.password
Queue Illuminate\Queue\QueueManager queue
Queue (實例) Illuminate\Queue\QueueInterface
Queue (基礎(chǔ)類) Illuminate\Queue\Queue
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\Database redis
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Blueprint
Session Illuminate\Session\SessionManager session
Session (實例) Illuminate\Session\Store
Storage Illuminate\Contracts\Filesystem\Factory filesystem
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (實例) Illuminate\Validation\Validator
View Illuminate\View\Factory view
View (實例) Illuminate\View\View
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 介紹 Facades 為應(yīng)用的 IoC 服務(wù)容器 的類提供了一個靜態(tài)的接口。Laravel 里面自帶了一些 Fac...
    伊Summer閱讀 11,173評論 0 11
  • Laravel 學(xué)習(xí)交流 QQ 群:375462817 本文檔前言Laravel 文檔寫的很好,只是新手看起來會有...
    Leonzai閱讀 8,716評論 2 12
  • 原文鏈接 必備品 文檔:Documentation API:API Reference 視頻:Laracasts ...
    layjoy閱讀 8,712評論 0 121
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,706評論 18 399
  • 聽說: navigationController已經(jīng)實現(xiàn)了右滑返回上一頁. 然后打聽度娘之后, 發(fā)現(xiàn)iOS7出來了...
    L_zix閱讀 604評論 0 0

友情鏈接更多精彩內(nèi)容