美文网首页
laravel工作流程以及自定义provider创建

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

作者: jacklin1992 | 来源:发表于2016-10-18 21:52 被阅读6335次

    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了

    相关文章

      网友评论

          本文标题:laravel工作流程以及自定义provider创建

          本文链接:https://www.haomeiwen.com/subject/hvgzyttx.html