An elegant design pattern
We often use some classes this way
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Log;
class IndexController extends Controller
{
public function index()
{
Log::info('hahaha~'); }}Copy the code
Register the alias
Start by looking at the part of the corresponding Log class registered in the framework, in the app.php file alias array
'aliases' => [
...
'Log'=> Illuminate\Support\Facades\Log::class, ... ] .Copy the code
So the actual container is going to parse when you call it
Lluminate, Support, Facades, Log: : class – this class
Let’s look at this class
<? php namespace Illuminate\Support\Facades; class Log extends Facade { protected staticfunction getFacadeAccessor()
{
return 'log'; }}Copy the code
Call analysis
The initial method we call is Log::info and we trace it to the parent Facade
Easy to read to simplify some methods
<? php namespace Illuminate\Support\Facades; use Closure; use Mockery; use RuntimeException; use Mockery\MockInterface; abstract class Facade { protected static$app;
protected static $resolvedInstance; . public staticfunction __callStatic($method.$args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args); }}Copy the code
The call logic here is implemented through the __callStatic magic method
public static function __callStatic($method.$args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
Copy the code
This explains why we can call the corresponding method statically.
To analyze
$instance = static::getFacadeRoot();
Copy the code
It looks like we’re trying to parse out an instance, but the important thing here is
static
The call will point to the calling class, followed by the inherited class.
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
Copy the code
So here’s the static: : getFacadeAccessor actually point to the Log () class
protected static function getFacadeAccessor()
{
return 'log';
}
Copy the code
Get an alias from the container
Let’s move on to how to get a date. Okay
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
if (isset(static::$resolvedInstance[$name]) {return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
Copy the code
$app[$name] static::$app[$name
Develop –$app
From where?
But where is $app assigned if it is an Application object?
Please refer to chapter 4 of Laravel- One Piece series, the handle method of Kernel class parsing.
protected $bootstrappers= [ ... \Illuminate\Foundation\Bootstrap\RegisterFacades::class, ... ] ;Copy the code
Go straight to code
<? php namespace Illuminate\Foundation\Bootstrap; use Illuminate\Foundation\AliasLoader; use Illuminate\Support\Facades\Facade; use Illuminate\Foundation\PackageManifest; use Illuminate\Contracts\Foundation\Application; class RegisterFacades { publicfunction bootstrap(Application $app)
{
Facade::clearResolvedInstances();
Facade::setFacadeApplication($app);
AliasLoader::getInstance(array_merge(
$app->make('config')->get('app.aliases', []),
$app->make(PackageManifest::class)->aliases() ))->register(); }}Copy the code
Delicious ~, the Facade: : setFacadeApplication ($app); Application passed in here.
$app[‘log’] $app[‘log’] $app[‘log’]
Extension – Container binding and parsing!
Chapter 3: Container Class Parsing
The bind() method inside binds the abstraction to the implementation in the container,
This is also container knowledge. The log here is the Application started in advance and helped us to fix ~
Located in __construct() of Application
public function __construct($basePath = null)
{
...
$this->registerBaseServiceProviders(); . }Copy the code
protected function registerBaseServiceProviders() {...$this->register(new LogServiceProvider($this)); . }Copy the code
<? php namespace Illuminate\Log; use Illuminate\Support\ServiceProvider; class LogServiceProvider extends ServiceProvider { publicfunction register()
{
$this->app->singleton('log'.function () {
return new LogManager($this->app); }); }}Copy the code
Return new LogManager($this->app);
finishing
Object in hand, you can arbitrarily call existing methods.
return $instance->$method(... $args);