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了