I've kind of looking at what's going on Laravel 4 facades under the hood.
Let's take this Facade as an example:
File::get(someArgs);
If i'm not mistaken, the step by step (oversimplified) invocation would be:
//static method invocation which are all extended from Facade class
File::__callStatic(get, someArgs)
//returns an instance of FileSystem
File::resolveFacedeInstance('files')
FileSystem->get(someArgs)
What I'am confused about is in the commented line below of the method File::resolveFacadeInstance() below:
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) return $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
/**
* The line that i'm confused about
*/
return static::$resolvedInstance[$name] = static::$app[$name];
}
My questions are:
If File::get() is the invoked Facade
static::$app[$name] would resolve to i think Application['files'] or Application->files which in turn calls Application->__get('files') since there's no files property inside Application class.
How would FileSystem Class be return if this is only the content of this method?
public function __get($key)
{
return $this[$key];
}
How Facades Work. In a Laravel application, a facade is a class that provides access to an object from the container. The machinery that makes this work is in the Facade class. Laravel's facades, and any custom facades you create, will extend the base Illuminate\Support\Facades\Facade class.
Laravel includes the ability to seed your database with data using seed classes. All seed classes are stored in the database/seeders directory. By default, a DatabaseSeeder class is defined for you. From this class, you may use the call method to run other seed classes, allowing you to control the seeding order.
Contracts Vs.Laravel's facades provide a simple way of utilizing Laravel's services without needing to type-hint and resolve contracts out of the service container. However, using contracts allows you to define explicit dependencies for your classes. For most applications, using a facade is just fine.
All of Laravel's facades are defined in the Illuminate\Support\Facades namespace.
I'll try to describe in short :
So, you already know that resolveFacadeInstance
method is called via __callStatic
method of Facade
class and component's Facade (i.e. File extends Facade)
extends this Facade
class.
During the boot-up process of the framework, from public/index.php
following line starts the execution of bootstrap/start.php
file
$app = require_once __DIR__.'/../bootstrap/start.php';
So, in this (bootstrap/start.php
) file you can see some code like
// the first line, initiate the application
$app = new Illuminate\Foundation\Application;
// ...
// ...
// notice this line
require $framework.'/Illuminate/Foundation/start.php';
// ...
// last line
return $app;
In this code snippet, require $framework.'/Illuminate/Foundation/start.php';
line starts the execution of Foundation/start.php
file and in this file you may see something like this
// ...
Facade::clearResolvedInstances();
// Notice this line
Facade::setFacadeApplication($app);
This (given above) line sets application
instanse to $app
property in the Facade
class
// support/Facades/Facade.php
public static function setFacadeApplication($app)
{
static::$app = $app;
}
Then in the Foundation/start.php
file at the bottom, you can see something like this
/*
|--------------------------------------------------------------------------
| Register The Core Service Providers
|--------------------------------------------------------------------------
|
| The Illuminate core service providers register all of the core pieces
| of the Illuminate framework including session, caching, encryption
| and more. It's simply a convenient wrapper for the registration.
|
*/
$providers = $config['providers'];
$app->getProviderRepository()->load($app, $providers);
$app->boot();
In this code snippet given above, all the core components registered by the framework and as you know that, every component has a service provider class (i.e. FilesystemServiceProvider
) and in every service provider class there is a method register
which is (for FilesystemServiceProvider
)
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app['files'] = $this->app->share(function() { return new Filesystem; });
}
Well, in this case $this->app['files']
setting (return new Filesystem
) an anonymous function, which returns the filesystem
when gets executed
$this->app['files'] = $this->app->share(function() { return new Filesystem; });
to $app['files']
so, when you call the File::get()
, it finally calls the anonymous function and in this case, the following line
return static::$resolvedInstance[$name] = static::$app[$name];
Calls the function for static::$app['file'];
and this function returns the instance but before returning, it stores the instance in the $resolvedInstance
variable, so, next time it can return the instance from the variable without calling the anonymous function again.
So, it looks like that, static::$resolvedInstance[$name] = static::$app[$name];
calls the anonymous function which returns the instance and this function was registered earlier, when the app
was started through boot up process.
Important :
Application
extends Container
and Container
extends ArrayAccess class and that's why, a property of the $app
object could be (accessed) set/get using array notation.
I've tried to give you an idea but you have to look in to the code, step by step, you won't get it only reading/tracking the code once.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With