Laravel 6 核心概念(服务容器、服务提供者、facades、contracts、辅助函数、生命周期)

交流群 375462817
视频配套文档群文件里面可以下载。
快速入门 https://www.bilibili.com/video/av70545323/
模型关系 https://www.bilibili.com/video/av73028135/
认证授权 https://www.bilibili.com/video/av74879198/
OAuth 2.0 https://www.bilibili.com/video/av75125939/
核心概念 https://www.bilibili.com/video/av76060293/

核心概念

简介、服务容器、服务提供者、facade、contract、生命周期。

简介

我叫 Laravel。我是一个装了药的药箱,专门处理人们的问题、治病。

人们喜欢把我的药箱叫做 service container 服务容器。

把我的药箱里面的一块一块的小格子叫 service provider 服务提供者。在这些小格子里可以放置不同的药。

有的人用到我的时候,会在我的小格子或者是他们自制的格子里面放置自己制作的药。有些药有副作用,比如可以治疗肚子疼又能治疗头痛,这样肚子疼、头不疼的患者吃了可能对头产生不良影响。所以我定了一份合同契约让放进来的药有个规范。并且我内置的药也是有契约来规范约束我自己。他们把我的这个合同称为 contract 契约。

有些药片很难看,可以把它用糖衣包装起来,这样小孩子更容易吞食使用。我里面很多药都用了这种包装,药效没增加,但是更容易使用。人们后期添加的药也可以自制包装。这种包装称之为 facade 门面。

一、药箱(服务容器)

绑定,解析,解析事件(类似于在药瓶中放药,取药,取药事项)。

放药(绑定)

基础绑定

$this->app->bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
});

绑定单例

$this->app->singleton('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
});

绑定实例

$api = new HelpSpot\API(new HttpClient);

$this->app->instance('HelpSpot\API', $api);

绑定实例时给定初始化数据

$this->app->when('App\Http\Controllers\UserController')
          ->needs('$variableName')
          ->give($value);    // 利用上下文给绑定设置初始数据

举个栗子

interface Fruit
{
    public function color();
}

class Apple implements Fruit
{
    public $color;

    public function __construct($color){
        $this->color = $color;
    }

    public function color(){
        return $this->color;
    }
}

app()->bind('Fruit', 'Apple');
app()->when('Apple')->needs('$color')->give('red');
echo app('Fruit')->color();

绑定接口到实例

$this->app->bind(
    'App\Contracts\EventPusher',
    'App\Services\RedisEventPusher'
);

根据上下文提供不同的绑定

$this->app->when(PhotoController::class)
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('local');
          });

$this->app->when([VideoController::class, UploadController::class])
          ->needs(Filesystem::class)
          ->give(function () {
              return Storage::disk('s3');
          });

给绑定设置标签

$this->app->bind('SpeedReport', function () {
    //
});

$this->app->bind('MemoryReport', function () {
    //
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

$this->app->bind('ReportAggregator', function ($app) {
    return new ReportAggregator($app->tagged('reports'));
});

Service 已经被解析,extend 方法可以用来修改解析出来的实例 $service

$this->app->extend(Service::class, function ($service, $app) {
    return new DecoratedService($service);
});
拿药(解析)
$this->app->make('HelpSpot\API');
app()->make('HelpSpot\API');
resolve('HelpSpot\API');
app('HelpSpot\API');
app()['HelpSpot\API']
app()->get('HelpSpot\API')
public function xxx(HelpSpot\API $users)
// 注入依赖
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
$api = app('HelpSpot\API', ['id' => 1]); 
$api = resolve('HelpSpot\API', ['id' => 1]); 
# laravel 实现了 PSR-11 接口,所以就可以用该接口的类型提示解析
use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {
    $service = $container->get('Service');
    //
});
容器事件

容器解析任何对象时调用

$this->app->resolving(function ($object, $app) {
    
});

容器解析HelpSpot\API时调用

$this->app->resolving(HelpSpot\API::class, function ($api, $app) {
    
});

二、药箱里的小格子(服务提供者)

制作一个服务提供者
  1. php artisan make:provider RiakServiceProvider
  2. 服务提供者主要由两个方法:registerbootregister 只负责绑定一些东西到容器(放药)。boot 可以使用类型提示解析等来完成任意你想做的事情,这些都归功于容器调用所有服务提供者的register方法之后才去调用boot方法。
  3. config/app.phpproviders数组中注册服务提供者。
制作一个延迟服务提供者

如果只是绑定服务到服务容器,可以设置为延迟(实现 DeferrableProvider 接口),在项目真正需要用到之前不会注册。

class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }

    public function provides()
    {
        return [Connection::class];
    }
}

三、Facades

不要在一个类中,用太多的facades。过于臃肿的情况下应该将大类分解成几个小类。

优点

方便测试(辅助函数和 facades 没什么区别,测试方法也是一样的)。

Route::get('/cache', function () {
    return Cache::get('key');     // === return cache('key');
});
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}
实时的 facades

原生用法 vs 实时用法

# 原生用法 class Podcast
use App\Contracts\Publisher;
public function publish(Publisher $publisher)
{
    $this->update(['publishing' => now()]);
    $publisher->publish($this);
}
# 实时用法
use Facades\App\Contracts\Publisher;

Publisher::publish($this);

测试实时的 facades

use Facades\App\Contracts\Publisher;
Publisher::shouldReceive('publish')->once()->with($podcast);
facades 列表
FacadeClassService Container Binding
AppIlluminate\Foundation\Applicationapp
ArtisanIlluminate\Contracts\Console\Kernelartisan
AuthIlluminate\Auth\AuthManagerauth
Auth (Instance)Illuminate\Contracts\Auth\Guardauth.driver
BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
BroadcastIlluminate\Contracts\Broadcasting\Factory 
Broadcast (Instance)Illuminate\Contracts\Broadcasting\Broadcaster 
BusIlluminate\Contracts\Bus\Dispatcher 
CacheIlluminate\Cache\CacheManagercache
Cache (Instance)Illuminate\Cache\Repositorycache.store
ConfigIlluminate\Config\Repositoryconfig
CookieIlluminate\Cookie\CookieJarcookie
CryptIlluminate\Encryption\Encrypterencrypter
DBIlluminate\Database\DatabaseManagerdb
DB (Instance)Illuminate\Database\Connectiondb.connection
EventIlluminate\Events\Dispatcherevents
FileIlluminate\Filesystem\Filesystemfiles
GateIlluminate\Contracts\Auth\Access\Gate 
HashIlluminate\Contracts\Hashing\Hasherhash
LangIlluminate\Translation\Translatortranslator
LogIlluminate\Log\LogManagerlog
MailIlluminate\Mail\Mailermailer
NotificationIlluminate\Notifications\ChannelManager 
PasswordIlluminate\Auth\Passwords\PasswordBrokerManagerauth.password
Password (Instance)Illuminate\Auth\Passwords\PasswordBrokerauth.password.broker
QueueIlluminate\Queue\QueueManagerqueue
Queue (Instance)Illuminate\Contracts\Queue\Queuequeue.connection
Queue (Base Class)Illuminate\Queue\Queue 
RedirectIlluminate\Routing\Redirectorredirect
RedisIlluminate\Redis\RedisManagerredis
Redis (Instance)Illuminate\Redis\Connections\Connectionredis.connection
RequestIlluminate\Http\Requestrequest
ResponseIlluminate\Contracts\Routing\ResponseFactory 
Response (Instance)Illuminate\Http\Response 
RouteIlluminate\Routing\Routerrouter
SchemaIlluminate\Database\Schema\Builder 
SessionIlluminate\Session\SessionManagersession
Session (Instance)Illuminate\Session\Storesession.store
StorageIlluminate\Filesystem\FilesystemManagerfilesystem
Storage (Instance)Illuminate\Contracts\Filesystem\Filesystemfilesystem.disk
URLIlluminate\Routing\UrlGeneratorurl
ValidatorIlluminate\Validation\Factoryvalidator
Validator (Instance)Illuminate\Validation\Validator 
ViewIlluminate\View\Factoryview
View (Instance)Illuminate\View\View

四、Contracts

FacadesContracts 没有什么值得注意的区别,但是当你开发第三方包的时候,最好使用 Contracts,这样有利于你编写测试,否则如果使用 Facades,因为是第三方包,将不能访问 facade 测试函数。

使用方法

在构造函数中类型提示注入就行了。

Contracts 列表
ContractReferences Facade
Illuminate\Contracts\Auth\Access\Authorizable 
Illuminate\Contracts\Auth\Access\GateGate
Illuminate\Contracts\Auth\Authenticatable 
Illuminate\Contracts\Auth\CanResetPassword 
Illuminate\Contracts\Auth\FactoryAuth
Illuminate\Contracts\Auth\GuardAuth::guard()
Illuminate\Contracts\Auth\PasswordBrokerPassword::broker()
Illuminate\Contracts\Auth\PasswordBrokerFactoryPassword
Illuminate\Contracts\Auth\StatefulGuard 
Illuminate\Contracts\Auth\SupportsBasicAuth 
Illuminate\Contracts\Auth\UserProvider 
Illuminate\Contracts\Bus\DispatcherBus
Illuminate\Contracts\Bus\QueueingDispatcherBus::dispatchToQueue()
Illuminate\Contracts\Broadcasting\FactoryBroadcast
Illuminate\Contracts\Broadcasting\BroadcasterBroadcast::connection()
Illuminate\Contracts\Broadcasting\ShouldBroadcast 
Illuminate\Contracts\Broadcasting\ShouldBroadcastNow 
Illuminate\Contracts\Cache\FactoryCache
Illuminate\Contracts\Cache\Lock 
Illuminate\Contracts\Cache\LockProvider 
Illuminate\Contracts\Cache\RepositoryCache::driver()
Illuminate\Contracts\Cache\Store 
Illuminate\Contracts\Config\RepositoryConfig
Illuminate\Contracts\Console\Application 
Illuminate\Contracts\Console\KernelArtisan
Illuminate\Contracts\Container\ContainerApp
Illuminate\Contracts\Cookie\FactoryCookie
Illuminate\Contracts\Cookie\QueueingFactoryCookie::queue()
Illuminate\Contracts\Database\ModelIdentifier 
Illuminate\Contracts\Debug\ExceptionHandler 
Illuminate\Contracts\Encryption\EncrypterCrypt
Illuminate\Contracts\Events\DispatcherEvent
Illuminate\Contracts\Filesystem\CloudStorage::cloud()
Illuminate\Contracts\Filesystem\FactoryStorage
Illuminate\Contracts\Filesystem\FilesystemStorage::disk()
Illuminate\Contracts\Foundation\ApplicationApp
Illuminate\Contracts\Hashing\HasherHash
Illuminate\Contracts\Http\Kernel 
Illuminate\Contracts\Mail\MailQueueMail::queue()
Illuminate\Contracts\Mail\Mailable 
Illuminate\Contracts\Mail\MailerMail
Illuminate\Contracts\Notifications\DispatcherNotification
Illuminate\Contracts\Notifications\FactoryNotification
Illuminate\Contracts\Pagination\LengthAwarePaginator 
Illuminate\Contracts\Pagination\Paginator 
Illuminate\Contracts\Pipeline\Hub 
Illuminate\Contracts\Pipeline\Pipeline 
Illuminate\Contracts\Queue\EntityResolver 
Illuminate\Contracts\Queue\FactoryQueue
Illuminate\Contracts\Queue\Job 
Illuminate\Contracts\Queue\MonitorQueue
Illuminate\Contracts\Queue\QueueQueue::connection()
Illuminate\Contracts\Queue\QueueableCollection 
Illuminate\Contracts\Queue\QueueableEntity 
Illuminate\Contracts\Queue\ShouldQueue 
Illuminate\Contracts\Redis\FactoryRedis
Illuminate\Contracts\Routing\BindingRegistrarRoute
Illuminate\Contracts\Routing\RegistrarRoute
Illuminate\Contracts\Routing\ResponseFactoryResponse
Illuminate\Contracts\Routing\UrlGeneratorURL
Illuminate\Contracts\Routing\UrlRoutable 
Illuminate\Contracts\Session\SessionSession::driver()
Illuminate\Contracts\Support\Arrayable 
Illuminate\Contracts\Support\Htmlable 
Illuminate\Contracts\Support\Jsonable 
Illuminate\Contracts\Support\MessageBag 
Illuminate\Contracts\Support\MessageProvider 
Illuminate\Contracts\Support\Renderable 
Illuminate\Contracts\Support\Responsable 
Illuminate\Contracts\Translation\Loader 
Illuminate\Contracts\Translation\TranslatorLang
Illuminate\Contracts\Validation\FactoryValidator
Illuminate\Contracts\Validation\ImplicitRule 
Illuminate\Contracts\Validation\Rule 
Illuminate\Contracts\Validation\ValidatesWhenResolved 
Illuminate\Contracts\Validation\ValidatorValidator::make()
Illuminate\Contracts\View\Engine 
Illuminate\Contracts\View\FactoryView
Illuminate\Contracts\View\ViewView::make()

五、请求生命周期

本节主要概括了框架运行的生命周期。

  1. 所有请求必定首先通过 public/index.php
  2. 在上述这个文件中首先加载 composer 自动加载文件,然后从 bootstrap/app.php 实例化一个服务容器。
  3. 接下来,框架会根据请求类型传送请求至 app/Http/Kernel.php 或者 app/Console/Kernel.php
  4. app/Http/Kernel.php扩展了Illuminate\Foundation\Http\Kernel类,父类强制在处理请求前应该做哪些操作,操作内容都放到了 bootstrappers数组里面(配置错误处理、配置记录日志、检测应用环境、注册和启动服务提供者等)。子类在数组middleware中规定了请求在被处理前必须经过的一些处理(读写session、判断是否处于维护模式、验证 csrf 令牌等)。
  5. 处理请求,返回响应内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值