Laravel类加载
对于很多新手来说,比如我,刚开始不是很习惯于Laravel这样的类加载。对于第三方拓展,Laravel的加载方式:
- 为这个类提供一个provider,继承ServiceProvider
- 重写register方法,singleton或者bind两种方式
- boot是当前类有依赖其他通过register注册,但是不确定先后顺序的时候使用
- $defer为true表示延迟加载,默认在Application初始化的时候加载
- config/app.php配置providers和aliases
- providers就是执行provider里面定义的register,具体方法是在Application中registerConfiguredProviders,但是aliases是用来做什么的还得再看看。
依赖注入
DI 官方定义是,就是一个类把自己的的控制权交给另外一个对象,类间的依赖由这个对象去解决。
Laravel的依赖注入真的很好用,我刚开始接触Laravel的时候,对于第三方的类,总是习惯于手动初始化。Laravel提供了一种方式,在传参数的时候,通过参数类型+参数名的方式指定。
这种方式的好处是,如果第三方的类有提供provider的方法,比如:
class RedisServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('redis', function ($app) {
return new Database($app['config']['database.redis']);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['redis'];
}
}
我们在通过Redis $redis这种方式注入的时候,实际拿到的是new Database($app[‘config’][‘database.redis’])。而且因为provider使用的是singleton方式,实现了单例,在这一次请求过程中,我们使用的都是同一个redis实例。
当然通过singleton绑定的还可以用app(‘redis’)这种方式来操作redis。
门面
Laravel的门面使用起来,习惯了IDE的话,如果使用门面来调用方法,在追代码的时候,不能直接跳转到代码的位置就。。
在定义一个门面的时候,都是继承Facade类,实现getFacadeAccessor()方法。
class Log extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'log';
}
}
abstract class Facade
{
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
switch (count($args)) {
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array([$instance, $method], $args);
}
}
}
我们再使用Log::info这种方式的时候,其实Log这个facade是没有info方法的,它是通过__callStatic,在__callStatic又通过getFacadeRoot拿到app中log的具体实现。
而关于log的使用会在下一篇博客里面提及。