LogoNavigate back to the homepage

How does config:cache work in Laravel?

Yish
February 23rd, 2020 · 1 min read

We all know if you want to accelerate performance in Laravel, you can do a lot of things, one of the things is cache what you think, likely route, config, view, etc, but how does it work in Laravel?

To be noticed, cache DOES NOT cache your environment variables, there is documentation in official describe.

Upgrade Guide - Laravel - The PHP Framework For Web Artisans

Caching And Env If you are using the config:cache command during deployment, you must make sure that you are only calling the env function from within your configuration files, and not from anywhere else in your application. If you are calling env from within your application, it is strongly recommended you add proper configuration values to your configuration files and call env from that location instead, allowing you to convert your env calls to config calls.

When you type $ php artisan config:cache what happen to your application?

Calling your binding command class
1//Illuminate\Foundation\Console\ConfigCacheCommand
2
3public function handle()
4{
5 $this->call('config:clear'); // clear your config cached if it exists.
6
7 $config = $this->getFreshConfiguration(); // get a new config
8
9 $configPath = $this->laravel->getCachedConfigPath(); // get cache file path
10
11 $this->files->put(
12 $configPath, '<?php return '.var_export($config, true).';'.PHP_EOL
13 ); // put the cached file.
14
15 try {
16 require $configPath; // if it generated successful, require the file.
17 } catch (Throwable $e) { // php7 error exception handle.
18 $this->files->delete($configPath); // delete failed file.
19
20 // throwing a logic exception to tell you, oh, something wents wrong.
21 throw new LogicException('Your configuration files are not serializable.', 0, $e);
22 }
23
24 // otherwise it's successful.
25 $this->info('Configuration cached successfully!');
26}

Next, we explore the method getFreshConfiguration

1protected function getFreshConfiguration()
2{
3 $app = require $this->laravel->bootstrapPath().'/app.php'; // require application kernel of laravel.
4
5 $app->useStoragePath($this->laravel->storagePath()); // storage path.
6
7 $app->make(ConsoleKernelContract::class)->bootstrap(); // bootstraping instanced of ConsoleKernelContract class.
8
9 return $app['config']->all(); // get all of config variables.
10}

To see getCachedConfigPath and normalizeCachePath

1// Illuminate\Foundation\Application
2
3public function configurationIsCached()
4{
5 return file_exists($this->getCachedConfigPath());
6}
7
8public function getCachedConfigPath()
9{
10 return $this->normalizeCachePath('APP_CONFIG_CACHE', 'cache/config.php');
11}
12
13protected function normalizeCachePath($key, $default)
14{
15 if (is_null($env = Env::get($key))) {
16 return $this->bootstrapPath($default);
17 }
18
19 return Str::startsWith($env, '/')
20 ? $env
21 : $this->basePath($env);
22}
23
24// Deal with your bootstrap path
25public function bootstrapPath($path = '')
26{
27 return $this->basePath.DIRECTORY_SEPARATOR.'bootstrap'.($path ? DIRECTORY_SEPARATOR.$path : $path);
28}
29
30// Deal with your base path
31public function basePath($path = '')
32{
33 return $this->basePath.($path ? DIRECTORY_SEPARATOR.$path : $path);
34}

But here is a problem, the laravel how to know to load your configs cached or not?

1// Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables
2public function bootstrap(Application $app)
3{
4 if ($app->configurationIsCached()) { // if it cached, return empty
5 return;
6 }
7
8 $this->checkForSpecificEnvironmentFile($app);
9
10 try {
11 $this->createDotenv($app)->safeLoad();
12 } catch (InvalidFileException $e) {
13 $this->writeErrorAndDie($e);
14 }
15}
16
17// check environment.
18protected function checkForSpecificEnvironmentFile($app)
19{
20 if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
21 if ($this->setEnvironmentFilePath(
22 $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
23 )) {
24 return;
25 }
26 }
27
28 $environment = Env::get('APP_ENV');
29
30 if (! $environment) {
31 return;
32 }
33
34 $this->setEnvironmentFilePath(
35 $app, $app->environmentFile().'.'.$environment
36 );
37}

And now we return back to see getFreshConfiguration and you are seeing

1$app->make(ConsoleKernelContract::class)->bootstrap();
1//Illuminate\Foundation\Console\Kernel <-- instance of ConsoleKernelContract
2protected $bootstrappers = [
3 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, //HERE
4 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
5 \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
6 \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
7 \Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
8 \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
9 \Illuminate\Foundation\Bootstrap\BootProviders::class,
10];
11
12public function bootstrap()
13{
14 if (! $this->app->hasBeenBootstrapped()) {
15 $this->app->bootstrapWith($this->bootstrappers()); //bootstrapping.
16 }
17
18 $this->app->loadDeferredProviders();
19
20 if (! $this->commandsLoaded) {
21 $this->commands();
22
23 $this->commandsLoaded = true;
24 }
25}

Next, seeing Illuminate\Foundation\Bootstrap\LoadConfiguration::class

1// Illuminate\Foundation\Bootstrap\LoadConfiguration
2
3public function bootstrap(Application $app)
4{
5 $items = [];
6
7 // First we will see if we have a cache configuration file. If we do, we'll load
8 // the configuration items from that file so that it is very quick. Otherwise
9 // we will need to spin through every configuration file and load them all.
10
11 // Here is the key, if cached file exists, require it. ^^^ see upon description.
12 if (file_exists($cached = $app->getCachedConfigPath())) {
13 $items = require $cached;
14
15 $loadedFromCache = true;
16 }
17
18 // Next we will spin through all of the configuration files in the configuration
19 // directory and load each one into the repository. This will make all of the
20 // options available to the developer for use in various parts of this app.
21 $app->instance('config', $config = new Repository($items));
22
23 if (! isset($loadedFromCache)) {
24 $this->loadConfigurationFiles($app, $config);
25 }
26
27 // Finally, we will set the application's environment based on the configuration
28 // values that were loaded. We will pass a callback which will be used to get
29 // the environment in a web context where an "--env" switch is not present.
30 $app->detectEnvironment(function () use ($config) {
31 return $config->get('app.env', 'production');
32 });
33
34 date_default_timezone_set($config->get('app.timezone', 'UTC'));
35
36 mb_internal_encoding('UTF-8');
37}

For now, we all knew how does it work about config cache, at last, I found a tip about load bootstrap loading. If you want to load the environment after bootstrapping, you can use afterLoadingEnvironment closure.

1public function afterLoadingEnvironment(Closure $callback)
2{
3 return $this->afterBootstrapping(
4 LoadEnvironmentVariables::class, $callback
5 );
6}

Cheers!

More articles from Yish

Laravel passport prune / revoke token event listeners

I found serveral examples, but I used two examples and sort up it, here is solution: stack overflow official Firstly, you need to add two…

December 26th, 2019 · 1 min read

Creating .mdx file support and snippet in VSCode

Recently I used `.mdx` file to write my post, I found VSCode doesn't support `.mdx` by default. So how to do it to support mdx?

December 8th, 2019 · 1 min read
© 2019–2020 Yish
Link to $https://twitter.com/yishlaiLink to $https://github.com/Mombuyish