Last active
July 2, 2021 15:34
-
-
Save Elandlord/0d1581c409d9241ccdf44b1929df70e0 to your computer and use it in GitHub Desktop.
Preloader class for Laravel (by Brent Roose)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Preloader | |
{ | |
private array $ignores = []; | |
private static int $count = 0; | |
private array $paths; | |
private array $fileMap; | |
public function __construct(string ...$paths) | |
{ | |
$this->paths = $paths; | |
// We'll use composer's classmap | |
// to easily find which classes to autoload, | |
// based on their filename | |
$classMap = require __DIR__ . | |
'/vendor/composer/autoload_classmap.php'; | |
// We flip the array, so that file paths are the array keys | |
// With it, we can search the corresponding class by its path | |
$this->fileMap = array_flip($classMap); | |
} | |
public function paths(string ...$paths): Preloader | |
{ | |
$this->paths = array_merge( | |
$this->paths, | |
$paths | |
); | |
return $this; | |
} | |
public function ignore(string ...$names): Preloader | |
{ | |
$this->ignores = array_merge( | |
$this->ignores, | |
$names | |
); | |
return $this; | |
} | |
public function load(): void | |
{ | |
// We'll loop over all registered paths | |
// and load them one by one | |
foreach ($this->paths as $path) { | |
$this->loadPath(rtrim($path, '/')); | |
} | |
$count = self::$count; | |
echo "[Preloader] Preloaded {$count} classes" . PHP_EOL; | |
} | |
private function loadPath(string $path): void | |
{ | |
// If the current path is a directory, | |
// we'll load all files in it | |
if (is_dir($path)) { | |
$this->loadDir($path); | |
return; | |
} | |
// Otherwise we'll just load this one file | |
$this->loadFile($path); | |
} | |
private function loadDir(string $path): void | |
{ | |
$handle = opendir($path); | |
// We'll loop over all files and directories | |
// in the current path, | |
// and load them one by one | |
while ($file = readdir($handle)) { | |
if (in_array($file, ['.', '..'])) { | |
continue; | |
} | |
$this->loadPath("{$path}/{$file}"); | |
} | |
closedir($handle); | |
} | |
private function loadFile(string $path): void | |
{ | |
// We resolve the classname from composer's autoload mapping | |
$class = $this->fileMap[$path] ?? null; | |
// And use it to make sure the class shouldn't be ignored | |
if ($this->shouldIgnore($class)) { | |
return; | |
} | |
// Finally we require the path, | |
// causing all its dependencies to be loaded as well | |
opcache_compile_file($path); | |
self::$count++; | |
echo "[Preloader] Preloaded `{$class}`" . PHP_EOL; | |
} | |
private function shouldIgnore(?string $name): bool | |
{ | |
if ($name === null) { | |
return true; | |
} | |
foreach ($this->ignores as $ignore) { | |
if (strpos($name, $ignore) === 0) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
(new Preloader()) | |
->paths(__DIR__ . '/vendor/laravel') | |
->ignore( | |
\Illuminate\Filesystem\Cache::class, | |
\Illuminate\Log\LogManager::class, | |
\Illuminate\Http\Testing\File::class, | |
\Illuminate\Http\UploadedFile::class, | |
\Illuminate\Support\Carbon::class, | |
) | |
->load(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment