Understanding Laravel’s Real-Time Facades — How it works under the hood
It’s been a long time since I wrote any technical article. I have just checked and it’s been over a year! ¯\_(ツ)_/¯
I had never been that busy, but I was not able to learn anything new meanwhile that I could write in words. I would rather explain in some other articles what I did in those months. Let’s go through today’s article.
Real-Time Facades
Laravel’s Real-Time facades can treat regular classes like a facade without defining the facade class. But if you’re not familiar with the facade, then you can just check the following article and I believe you’ll get to know about Laravel’s facade and how to create your own.
The real-time facades acts like magic, but to understand the magic, you’ll need to understand how autoloading classes work in PHP.
Autoloading classes
When you’re writing a PHP application, in the beginning, the number of files is very few. In that case, you can just include the class files using include or require expressions. But as soon the project grows, the classes grow as well and writing require expressions for requiring those files don’t make sense. In that scenario, you should use SPL autoloading. Have you ever wondered why we require vendor/autoload.php
in our script when using with composer? If you have never thought that before, let me tell you that, it autoloads files for us.
Now, let’s get our hands dirty. This is what our simple project looks like.
- The app directory contains the
App
class. - The src directory contains the
Source
class. - The base/working directory contains the
Current
class.
The Current
class extends the Source
class, the Source
class extends the App
class. Look at the following codebase. Just a few simple classes.
Now, to instantiate the Current
class, we need to require that file along with dependent files. Without using the SPL autoloading, our index.php should look like the following.
Here, the order of require expression matters. Swapping lines 3, 4, 5 in any order doesn’t work other than this. So, you will have to be mindful to keep track of the order of imports.
Now, let’s look at the following example.
Line 3, 14, and 25 declares three functions. Each of these functions is liable for requiring the correct file from the correct directory.
- The
autoload_src
method is responsible to include files from the src directory. - The
autoload_app
method is responsible to include files from the app directory. - The
autoload_current
method is responsible to include files from the current directory.
Line 43, 44, 45 register the methods we have defined. The spl_autoload_register
accepts the first parameter, a callback. The second parameter $throw
should not be touched if using PHP ≥8.0 and finally, $prepend
the third parameter, determines if the callback should be placed at the top of the queue or at the bottom of the queue.
Line 47, prints out the available registered autoloading functions.
Line 51, echos out the return value from the class method.
Now, if we execute the script, it will produce the following output.
❯ php index.php
autoloader order:["autoload_current","autoload_app","autoload_src"].
autoload_current: looking for "Current".
autoload_current: looking for "Source\Source".
autoload_app: looking for "Source\Source".
autoload_src: Looking for "Source\Source".
autoload_current: looking for "App\App".
autoload_app: looking for "App\App".
Current says: "Hello anik."
If we check the order of the autoloader in the first line of the output, Line 43, 44, 45 will make sense now.
As we were instantiating the Current
class, the file was autoloaded by the autoload_current
method. The Current
class extends the Source
class. It should also be required in our script and that was done automatically. Only the autoload_src
could load the Source
class and the loader method was in the third position of the autoloader queue. This is why autoload_current, autoload_app ran before the autoload_src when loading the Source
class. The same thing happens to the App
class because it’s required by the Source
class.
So, now I believe that you have an understanding of how PHP autoloads the files.
Back to Real-Time Facades
- Laravel uses Composer and PSR-4 autoloading.
- In both cli-based entry point (artisan) and web-based entry point (public/index.php), it requires
vendor/autoload.php
that in turn registers an autoloader which is responsible for loading all the class files. - For both artisan and index.php, it registers required kernels.
- Based on the SAPI you use, it calls either of the HTTP Kernel’s bootstrap or Console Kernel’s bootstrap
- Both the kernels, at one point, call the RegisterFacades class’s bootstrap method.
- In turn, that calls the AliasLoader::prependToLoaderStack. This is where the
spl_autoload_register
method registers a new autoloader and pushes it to the top of the autoloader queue. - Then, when you call a class with
Facade\
prepended namespace, it calls the AliasLoader::load method where it checks and loads the facade class if possible.
And finally, you get your non-facade classes treated as a facade instance.
Maybe you can argue, what’s the point of doing it? Any privilege? IDK. I never used any of my regular classes like a facade. Also, for the last 6 years, I had been working with Lumen with facade disabled. So, I have no answer to your question. ¯\_(ツ)_/¯
That’s all for this article. Hope you understood how it actually works. But I’d like to let you do an exercise. It should also be possible to use MyFacade\
instead of the Facade\
prepended namespace. Can you figure out how to do it?
Anyway, Happy coding ❤