laravel工作流程以及自定义provider创建

2016-10-18  本文已影响6335人  jacklin1992

laravel 的整个框架中,任何一个模块都可以删除和修改,也可以任意增加自己的模块,这也是laravel的灵活和强大之处。

laravel工作流程以及自定义provider创建

首先 laravel构架的文件都在下面这个文件夹中

vendor/laravel/framework/src
具体流程

1.首先进入我们熟悉的public下面,这是项目访问的默认目录,打开index.php,加载了一个app文件

$app = require_once __DIR__.'/../bootstrap/app.php';

2.打开这个bootstrap/app.php,看到里面实例化了一个叫做Application的类

$app = new Illuminate\Foundation\Application(    realpath(__DIR__.'/../'));

3.打开这个文件,发现这个application文件继承了container对象

class Application extends Container

4.所以这个bootstrap下面的app.php其实是实例化了Application,而Application又继承自容器对象。

5.重新回到bootstrap/app.php,发现他在里面绑定了很多类并返回,
每个绑定里面有两个类,第一个是接口,第二个才是真正的类。

  $app->singleton(Illuminate\Contracts\Http\Kernel::class,    App\Http\Kernel::class);
    ......
    return $app;

6.所以我们自己也可以在这里绑定我们自己写的类,并通过下面两种方法来调用。

//绑定自己的类
$app->singleton('Test',App\Http\Test);
//调用(全局环境下)
$u = $this->app->make('Test');
$u = $this->appp['Test'];

这个就叫做工厂模式,所谓工厂的意思就是,以前你要每次实例化一个类才能获得这个类的方法属性,但是现在你可以通过make(),或app[''],得到这个类。

7.假如你写了以下两个对象,将Ta对象作为参数传入Tb对象的构造函数中,将会自动为你实例化Ta类为ta,这个叫做依赖注入,经常看到的(REQUEST $request),就是这个道理。但是前提是你的Ta 和Tb类都已经绑定注册过了。

class Ta
{
  public $jacklin;
   public function test()    
  {       
 echo 'tb';   
  }
}
 class Tb
{
    private $ta;

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

    public function test()
    {
       echo "tb";
    }
}

8.刚才说到,我们自定义的对象可以在bootstrap/app.php中绑定注册,但是这个文件是个入口文件,多人合作的项目中,合并版本的时候会遇到冲突,所以要有一个合适的位置进行注册绑定的步骤。全局唯一的文件肯定不合适,那么控制器能不能注册呢,不行,比如(Request $request)这个例子来说,肯定是要先已经注册过Request这个类,才能依赖注入,所以假如写在控制器有很多情况是无法使用我们注册的类的。那么重新回到开始的文件,在public/index.php下,除了刚才的加载app类,还有下面一句

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

这句话按照他的文件去找我是蒙逼了,但是大概的意思就是make了一个http的kernel内核,按照龙哥的指示,直接找到http下面的kernel

9.找到app/Http/Kernel之后发现他除了加载我们熟悉的中间件,还继承了一个内核文件

use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel{}

找到这个文件,发现下面的启动数组,环境,配置,处理异常等等。laravel会遍历这个数组,把里面的东西分别启动。

protected $bootstrappers = [
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',//config/app.php
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    'Illuminate\Foundation\Bootstrap\RegisterProviders',//注册服务提供者
    'Illuminate\Foundation\Bootstrap\BootProviders',
];

在加载配置的时候,程序会加载config里面中的app.php,有一段下面的程序,可以看到,他加载了所有的服务提供者的模块。并且 'Illuminate\Foundation\Bootstrap\RegisterProviders',会把app.php里面记录的的服务提供者都注册

  'providers' => [

    /*
     * Laravel Framework Service Providers...
     */
    Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
    Illuminate\Auth\AuthServiceProvider::class,
    Illuminate\Broadcasting\BroadcastServiceProvider::class,
    Illuminate\Bus\BusServiceProvider::class,
    Illuminate\Cache\CacheServiceProvider::class,
    Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
    Illuminate\Routing\ControllerServiceProvider::class,
    Illuminate\Cookie\CookieServiceProvider::class,
    Illuminate\Database\DatabaseServiceProvider::class,
    Illuminate\Encryption\EncryptionServiceProvider::class,
    Illuminate\Filesystem\FilesystemServiceProvider::class,
    Illuminate\Foundation\Providers\FoundationServiceProvider::class,
    Illuminate\Hashing\HashServiceProvider::class,
    Illuminate\Mail\MailServiceProvider::class,
    Illuminate\Pagination\PaginationServiceProvider::class,
    Illuminate\Pipeline\PipelineServiceProvider::class,
    Illuminate\Queue\QueueServiceProvider::class,
    Illuminate\Redis\RedisServiceProvider::class,
    Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
    Illuminate\Session\SessionServiceProvider::class,
    Illuminate\Translation\TranslationServiceProvider::class,
    Illuminate\Validation\ValidationServiceProvider::class,
    Illuminate\View\ViewServiceProvider::class,

    /*
     * Application Service Providers...
     */
    App\Providers\AppServiceProvider::class,
    App\Providers\AuthServiceProvider::class,
    App\Providers\EventServiceProvider::class,
    App\Providers\RouteServiceProvider::class,
], 

9.那么我们要注册的方法到底在哪里呢,找到App/Providers,随便打开里面的文件。发现下面代码

use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider

打开这个文件

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

发现这个类注入了app对象,所以在Provider的范围内也可以写

$this->app

重新回到刚才打开的AppServiceProvider,里面有一个注册方法

public function register()

这里就是我们要注册自己写的类的地方了,把我们绑定的语句写进来,注意是$this->app

public function register()
{
    $this->app->singleton(\App\Ta::class,\App\Ta::class);
    $this->app->singleton(\App\Tb::class,\App\Tb::class);
}

这里要注意命名空间的问题,App前面要加上\从根命名空间查找

这样,laravel加载内核文件的时候,就会将我们写好的服务提供者文件加载进去。

刚才是在AppServiceProvider中注册了我们的模块,那怎么创建自己的Provider呢,首先在同样的目录下创建文件JacklinServiceProvider.php,基础内容可以从别的Provider文件复制,然后同样在注册方法中写入自己的类,最后,还要在刚才的config\app.php中的,providers[]里面加入我们新的服务提供者类,OK了。

10.上面已经能够把我们自己写的模块加进去了,那还有一个问题,我们这样每次调用自己的模块都要通过工厂模式make出来,还是很麻烦,但是系统的方法似乎很简单,比如DB::,Input::,就 可以直接调用方法,这是为什么呢?laravel又提供了另外一个东西,叫做facades,这个单词的本意是门面的意思,下面开始解释这个东西。

首先随意创建一个Test.php,我们先创建在App\Http,写入以下内容

    <?php

namespace App\Http\Facades;

class Ta extends \Illuminate\Support\Facades\Facade
{
    protected static function getFacadeAccessor()
    {
        return '\App\Ta';
    }
}

从内容上不难看到,这是\Illuminate\Support\Facades\Facade,的一个方法,大概的意思就是把Ta这个对象实例化出来,并且嵌套在自己的一个静态方法里面,给这个class起个跟Ta一样的名字,那么当你Ta的时候,这个类也就加载了\App\Ta,所以就造成了Ta::也能用Ta里面的方法。

//调用
App\Http\Facades\Ta::test();

这么调用好像也很麻烦,怎么样能像DB::那样直接用呢,还有一步,配置aliases,本意别名

还是刚才的config/app.php中,在aliases中加入

'Jacklin'   => App\Http\Facades\Ta::class,

这样又把Ta类的方法转移到了Jacklin身上,试试,下面方法可以执行,一套自己的‘静态’provider就弄好了,而且还把访问的方式美化了,这也就是laravel用facader这个词命名这个方法的意思吧

Jacklin::test();    

11.最后刚才创建的这个JacklinServiceProvider.php是随便放了个文件夹,显然不合适,那么在app/Http 下面创建一个Facades文件夹,然后把JacklinServiceProvider.php放进去,并修改命名空间即可。

12.另外,我们的Ta Tb也是直接创建在了app里,同样的道理,在app/Http下建立Module文件夹,把我们的模块放进去。

总结

为了便于记忆,整理一下完成一个provider的思路。
1.建立Modules文件夹和Facades
2.在Modules建立模块文件Test.php
3.在Provider中建立TestServiceProvider.php,复制AppServiceProvider.php,里的基础内容,在register()方法中注册前面写的Test模块

  $this->app->singleton(\App\Http\Modules\Test::class,\App\Http\Modules\Test::class);

4.在config/app.php的providers[]中加入

App\Providers\TestServiceProvider::class,

5.在app/Http/Facades中建立Jacklin.php,模仿静态方法

<?php

namespace App\Http\Facades;

class Test extends \Illuminate\Support\Facades\Facade
{
    protected static function getFacadeAccessor()
    {
        return '\App\Http\Modules\Test';
    }
}

6.在config/app.php的aliases[]中加入

'Test' => App\Http\Facades\Test::class,

7.OK了

上一篇下一篇

猜你喜欢

热点阅读