From ce5aeeb28544b85150382989d463b8dc71efec87 Mon Sep 17 00:00:00 2001 From: Belle Aerni Date: Tue, 3 Oct 2023 06:13:17 -0700 Subject: [PATCH] Implemented classmap pruning method (#7) * Implemented classmap pruning method * Fixed some typos, improved the readme --- README.md | 21 +++++++++++++++------ src/AntLoader.php | 28 +++++++++++++++++++++++++--- tests/RandomClassesTest.php | 14 ++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b94d615..bc16fa2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # AntLoader + +[![Packagist Downloads](https://img.shields.io/packagist/dt/antcms/antloader)](https://packagist.org/packages/antcms/antloader) +[![PHP Tests](https://github.com/AntCMS-org/AntLoader/actions/workflows/tests.yml/badge.svg)](https://github.com/AntCMS-org/AntLoader/actions/workflows/tests.yml) +[![PHPStan](https://github.com/AntCMS-org/AntLoader/actions/workflows/phpstan.yml/badge.svg)](https://github.com/AntCMS-org/AntLoader/actions/workflows/phpstan.yml) + A small, simple, and highly performant autoloader for PHP applications. - Supports at least PHP 8.0 @@ -31,8 +36,8 @@ $loader->resetClassMap(); // Reset the classmap, clearing the existing one out f ``` ## Configuration -AntLoader accepts uses an array to configure it's available options. -None of the configuration options are required, however at a minimum it is recommended to specify a path unless you know APCu will be usable in all enviroments for your application. +AntLoader accepts an array to configure it's available options. +None of the configuration options are required, however at a minimum it is recommended to specify a path unless you know APCu will be usable in all environments for your application. **Note**: Please read the "Classmap Caching Options" section of this document, as that covers the strengths and weaknesses of each caching approach. ```PHP @@ -64,7 +69,7 @@ This feature allows AntLoader to achieve optimal performance by persisting the c Here are a few things to note about the APCu mode: - AntLoader generates a random key based on the directory it resides in. This ensures a unique key name to avoid accidentally overwriting APCu keys. The generated key remains static throughout the lifespan of the application. - - As long as you aren't running two seperate PHP applications & using the same copy of AntLoader (which you shouldn't be), this is sufficient to prevent issues. + - As long as you aren't running two separate PHP applications & using the same copy of AntLoader (which you shouldn't be), this is sufficient to prevent issues. - Depending on your web server configuration, using APCu may allow the classmap to be accessed by other PHP applications. However, in the case of AntLoader, this information only includes the namespaces/classes within your application and their respective paths. - By default, AntLoader stores the classmap with APCu using a Time-to-Live (TTL) of 7 days. @@ -75,7 +80,7 @@ Here are some details about the filesystem caching method: - By default, AntLoader saves the classmap to the system's temporary directory, which may not survive through multiple sessions. It is recommended to override the default path and specify a more persistent location. - The classmap file stored in the filesystem has no lifespan limit imposed by AntLoader. It will be retained until either you delete the file or call the `resetClassMap` function. - - Clearing or resetting the classmap is generally easier to perform outside of calling the resetClassMap function provided by AntLoader. + - Clearing or resetting the classmap is generally easier to perform outside of calling the `resetClassMap` function provided by AntLoader. ## Notes @@ -85,15 +90,19 @@ Here are some details about the filesystem caching method: - Depending on the setup, prepending AntLoader may speed up the performance of your application. - For example, if you are using composer's autoloader and have a lot of composer packages, that may delay the time it takes to load classes within your application. - In this example, the classes inside of your application will load slightly faster and classes loaded through composer will be slightly slower. - - Potential improvements are highly dependent on the specific application and enviroment. In most situations, the difference is likely to be very minimal. + - Potential improvements are highly dependent on the specific application and environment. In most situations, the difference is likely to be very minimal. So, we encourage you to take advantage of the classmap feature to get the best performance out of your application. ### Maintaining AntLoader -AntLoader is generally hands-off, except that we highly recomend clearing out / resetting the classmap after updating your application. +AntLoader is generally hands-off, except that we highly recommend clearing out / resetting the classmap after updating your application. AntLoader will **never** remove outdated classes / paths from the classmap, so never allowing it to be rebuilt can negatively affect the performance of your application if classes are renamed or moved. The best way to do this is simply to call the `resetClassMap` function that AntLoader provides. This will automatically reset the classmap for the current Cache method. +#### Pruning the classmap +If you have an application where the class list may periodically change, you can prune the classmap periodically to ensure it's not filling up with classes that no longer exist. +To do so, simply call `pruneClassmap`. This function will return the number of pruned classes. + ## License AntLoader is distributed with no warranty under the [Apache License 2.0](https://github.com/AntCMS-org/AntLoader/blob/main/LICENSE) diff --git a/src/AntLoader.php b/src/AntLoader.php index eefb7dd..91d942a 100644 --- a/src/AntLoader.php +++ b/src/AntLoader.php @@ -10,13 +10,13 @@ class AntLoader { private string $classMapPath = ''; - /** @var array> **/ + /** @var array> */ private array $psr0 = []; - /** @var array> **/ + /** @var array> */ private array $psr4 = []; - /** @var array **/ + /** @var array */ private array $classMap = []; private int $cacheType = 0; @@ -251,6 +251,28 @@ public function autoload(string $class): void } } + /** + * Prunes the classmap cache of any non-existant classes + * + * @return int The number of classes that was pruned. + */ + public function pruneClassmap(): int + { + $pruned = 0; + foreach ($this->classMap as $class => $path) { + if (!file_exists($path)) { + $pruned++; + unset($this->classMap[$class]); + } + } + + if ($pruned > 0) { + $this->saveMap(); + } + + return $pruned; + } + /** * @param string $class Classname, after having any specialized handling performed * @param string $path The path associated with the namespace diff --git a/tests/RandomClassesTest.php b/tests/RandomClassesTest.php index fd9424a..21463c1 100644 --- a/tests/RandomClassesTest.php +++ b/tests/RandomClassesTest.php @@ -131,3 +131,17 @@ $loader->resetClassMap(); deleteRandomClasses(); }); + +test('Prune classmap', function () { + // Test class loading with class map + deleteRandomClasses(); + createRandomClasses(10); + + $loader = setupLoader('filesystem'); + $loader->resetClassMap(); + $loader->checkClassMap(); + + deleteRandomClasses(); + + expect($loader->pruneClassmap())->toEqual(10); +});