laravel依赖注入、Facades的实例、工厂模式

Facades 工作原理#

  • 任何一个类里面,只要有构造函数依赖的,都可以注入

  • 服务提供者里面,registry方法是注册容器,boot方法是启动的时候进行的初始化工作,还有map方法,把服务提供者做一个映射

第一段

下面我做一个测试实现依赖注入

首先在app下面自己写一个类, vi /app/U.php

//  app/U.php
<?php
namespace App;
class U
{
    public function show()
    {
        return 'this is U show';
    }
}

然后我们在控制器里面的构造函数里实现注入。这样,整个控制器都可以使用U.php类里面的所有函数了

<?php
namespace App\Http\Controllers;
class TestController extends Controller
{
    protected $u;
    public function __construct(\App\U $a)
    {
        $this->u = $a;
    }
    public function test()
    {
        return $this->u->show();
    }
}
依赖注入打印结果
  • 我们也可以直接绑定(bind),然后直接生产(make)
Route::get('/test',function (){
    App::bind('U',function(){  
 // 这里使用$this->app->bind()应该也可以,但是我这里测试不成功,就换成了App这个静态方法了
        return new \App\U();    //   我们这里实例化那个类,就是绑定的哪个类
    });
    $res = App::make('U');
    return $res->show();
});

第二段

  • 但是我们如果能够直接用别名的方式来替代\App\U就更好了。那么我们就需要起一个别名。为了方便区分理解,我们此处把别名叫做UA

第一步:把U这个类,绑定(注册)至容器。

我们在app/Providers/AppServiceProvider.php里面注册U这个类,起个名字为UA.

public function register()
    {
        $this->app->bind('UA',function($app){
            return new \App\U();
        });
    }

第二步,使用Facades给绑定的UA做成静态方法

首先我们还是可以在app下面自己写一个类, vi /app/UF.php

<?php
//   app/UF.php
namespace App;
use Illuminate\Support\Facades\Facade;
class UF extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'UA';  //  此处返回的是服务容器中绑定的名字,我们刚才把`U.php`类绑定成了`UA`
    }
}

这个时候我们就可以使用静态方法UF就能替代U.php这个类了。不需要再在构造函数中注入了

<?php
namespace App\Http\Controllers;
class TestController extends Controller
{
   public function test()
    {
        return \App\UF::show();
    }
}
//  打印出来的结果,和依赖注入打印结果是一样的
image.png
image.png

第三段

  • 我们也可以给UF.php这个类起别名F
    很简单,只需要在第二段的基础上做修改。
    app/config/app.php里面的aliases数组里面添加'F' => \App\UF::class,即可。
把`UF.php类`注册别名
  • 这里我是为了方便大家区分,故意把注册的U.php类写成了,UA,UF,F。其实三个名字都应该写成U,这样才方便我们辨别。框架里面的都是统一的。比如下图的View类别名
图1.png

图2.png

还有一个问题就是,如果我们需要看框架里面那些类怎么办的。我们每次打开只能打开到图1的那种情况,我们可以看手册Facades章节的Facade 类参考#


一些听课笔记也在这里写下

  • 任何一个类里面,只要有构造函数依赖的,都可以注入
laravel中所谓的容器其实就是一个工厂,可以帮助我们创建对象。使用容器可以方便的实现创建某个接口的多个实现类。
容器剋在任何可以访问到app对象的地方绑定 (注册),但通常我们会在服务提供者的register方法中进行多个容器的绑定。
laravel框架默认为我们保留了一个服务提供者,AppServiceProvider.php 其中register是空白的,我们可以将自己的容器配置到里面。

Contracts 的好处是,我们的接口是一定的,但是我们的服务可以随便修改。这样做到了低耦合。

有了服务容器,我们才可以make 出来东西
没有在服务提供者里面注入的话,也make 不出来东西

服务提供者里面,register方法是注册容器,容器是帮我们创建对象的。不过,服务提供者本身,也需要被注册,就是在`app/config/app.php`里的`providers`数组里面
boot方法是启动的时候进行的初始化工作,还有map方法,把服务提供者做一个映射

laravel工厂模式

  • 其实服务提供者,就是框架给我们提供了一个可配置的工厂
  • 服务提供者是在框架里面为我们准备了一个类似于工厂的工具
  • 服务容器,就是具体的帮助我们实现依赖注入,控制反转的工具

所谓的工厂模式,就是我们需要什么类,我们就绑定什么类。比如刚才我们绑定了 U类,现在我们需要一个U2类,我们就直接绑定U2类.
但是此处的U2类,应该是与U类有一样的方法,一样的接口。这样,我们直接用F::方法中的方法都不需要改变。适用场景,比如原来用了mysql,现在改成orcal

public function register()
    {
        $this->app->bind('UA',function($app){
            return new \App\U();
        });
    }

laravel的服务提供者provider

简单讲解

其实服务提供者本质就是
1.注册一个类
2.生成一个继承ServiceProvider的 Provider 
在register 函数里面实现app的绑定这个类
3.在config/app.php的providers数组里面添加第二步生成的provider类
4.在使用的时候直接app('')或者app()->make('')即可
  • 实例演示
1.生成Billing类
<?php
namespace App;
class Billing{
    public function test()
    {
        return 'test';
    }
}

2.
php artisan make:provider  BillingProvider
修改里面的register函数
public function register()
    {
        $this->app->bind('billing',function (){
            return new \App\Billing();
        });
    }

3. config/zpp.php里面
'providers' => [
     .....
        \App\Providers\BillingProvider::class,

    ],
4 使用
public function index()
    {
        $res = app('billing');
// 或者   $res = app()->make('billing');
        dd($res->test());
    }
  
  • 如果想要实现facede也很简单,我们基于以上步骤来做
5.生成一个继承Facade的Bill类
<?php
namespace App;
use Illuminate\Support\Facades\Facade;

class Bill extends Facade {
    protected static function getFacadeAccessor()
    {
        return 'billing';  
    }
}

// 函数的return 必须是 billing  代表的是 Billing这个类
其实相当于是 app()->bind('billing')
Facade这个类中有public static function __callStatic($method, $args) 函数
如果我们使用的方法不存在,就会执行这个静态方法

6.config/app.php里面

'aliases' => [
'Bill' => \App\Bill::class,
]
这个时候,我们就可以直接
 public function index()
    {
        $res = Bill::test();
        dd($res);
    }
但是这种方式比provider多执行了一些东西,其实效率是偏慢的

服务容器
服务容器与容器与工厂

application是一个工厂
首先他要绑定一个类或者对象,然后才可以实例化使用

首先绑定一个类或者对象,同时给他起一个名字 
$this->app->bind('\A', function ($app) {    
  //1.使用绑定方法,回调函数都要return一个类型的对象   
        return new App\User();    
    });
//然后当你需要这个对象的时候,你就make生产   
 $u = $this->app->make('A');
 //$this->app->make('A') 等价于 $this->app['A'];


 singleton()绑定默认只会创建一个对象
$this->app->bind('\A', function () {       
        return new App\User();    
    });
$u = $this->app['A'];
 $u->title = 'abc';
 $u2 = $this->app['A'];
 dd($u2);  //打印出'abc
如果是singleton()只能创建一个对象

使用绑定方法,回调函数都要return一个类型的对象
你也可以使用 instance方法绑定一个已经存在的对象至容器中。后面的调用都会从容器中返回指定的实例:

     $this->app->bind('\A', function () {    
        return new App\User();    
    });
   这句话还可以写成  $this->app->bind('A',App\User::class);

    $api = new HelpSpot\API(new HttpClient);
    $this->app->instance('HelpSpot\Api', $api);

我们来看一个app/bootstrap/app.php中的一个绑定

    $app->singleton(    
     //这个只是一个接口,这个接口有很多的实现 
          Illuminate\Contracts\Http\Kernel::class,   
  //这个只是具体的实现这个接口的一个类
          App\Http\Kernel::class
    );


    绑定接口至实现
    $this->app->bind( 'App\Contracts\EventPusher',    //接口
                      'App\Services\RedisEventPusher'  //实现
                    );

依赖注入

一个工厂类来帮我们创建我们的对象的同时,把我们这个对象创建的时候需要的参数也一起注入进来
这个过程就叫做控制反转。把创建对象的责任交给容器,交给工厂,而不是我们自己

1.我们先创建两个类,比如在app目录下TA.php TB.php两个文件夹下两个类
namespace   App;
class TA
{
    private $title;
}

namespace   App;
class TB
{
    private $ta;
    public function __construct(\App\TA $a){
        $this->ta = $ta;
    }
}
   2.在app/bootstrap/app.php中写好一个绑定
  绑定的时候,如果命名空间从根目录下引用"\",则此命名空间加不加引号都行
   $app->bind( 'App\TA::class', '\App\TA::class');  //前面这个必须加引号,后面这个可写可不写
    $app->bind( '\App\TB::class', \App\TB::class);
    3.然后我们在路由页面随便做一个测试
    Route::get('/test',function(){
         $tb = $this->app->make( '\APP\TB::class' ); //引号可写可不写
         dd($tb);
     });

实现添加自己组建的流程

1.先在config/app.php里面的  providers 数组里面添加自己的 provider类
App\Library\Tool\ToolServiceProvider::class,
自己的provider类写在哪里都无所谓,只要跟数组中对上即可
2.在provider类里面  register 写入自己$this->app->singleton绑定的类,这个类是自己真正需要的功能类
singleton中第一个参数是随便的一个名称,第二个参数才是类名
3.创建一个facade类
protected static function getFacadeAccessor()
    {
        return \App\Library\Tool\source\Common::class;
    }
}
这个return中的值,其实是刚才singleton 绑定的第一个参数
4.在config/app.php中的aliases数组里面添加别名
 'Common' => App\Library\Tool\CommonFacade::class, 
这个值对应的是3中的类名
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 先说几句废话,调和气氛。事情的起由来自客户需求频繁变更,伟大的师傅决定横刀立马的改革使用新的框架(created ...
    wsdadan阅读 3,005评论 0 12
  • 我将人生用笔墨在纸间挥洒 是为了生命的自由 是为了诗一样的人生 是为了爱的自由 是为了前行的力量 —— 我厌恶思想...
    星辰溥天阅读 224评论 0 1
  • "得不到的永远在骚动,被偏爱的都有恃无恐" 我们每个人都曾经扮演过这两种角色 被偏爱 有恃无恐 得不到 诚惶诚恐 ...
    Sickosss阅读 276评论 0 0