Add Redis caching to autoloader for improved class and module loading performance

- Integrated Redis caching in the autoloading process to store and retrieve class and file paths dynamically.
- Added fallback mechanisms for Redis errors to ensure compatibility.
- Cached module directories and individual class paths with expiration to enhance performance and reduce filesystem scans.
This commit is contained in:
Jeppe Bundgaard
2026-02-24 13:55:34 +01:00
parent e8f0c630cf
commit 2534ffb1b9
+55 -7
View File
@@ -22,6 +22,18 @@ header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
/** Autoload */
require_once __DIR__ . '/vendor/autoload.php';
// Initialize Redis for autoload caching
require_once WD . '/interfaces/redis_i.php';
require_once WD . '/traits/redis_t.php';
require_once WD . '/classes/redis.php';
try {
$redis_instance = (new classes\redis())->connect();
define("redis", $redis_instance);
} catch (Exception $e) {
// Redis might not be available, autoloader will fall back to manual search
}
/**
* Lightweight project autoloader: load classes/interfaces/traits/modules on demand.
* Maps top-level namespaces to folders under the app root (WD).
@@ -35,6 +47,20 @@ require_once __DIR__ . '/vendor/autoload.php';
*/
spl_autoload_register(function (string $class): void {
$class = ltrim($class, '\\');
// Check Redis cache first
if (defined('redis')) {
try {
$cached = redis->get('autoload:' . $class);
if ($cached && is_file($cached)) {
require_once $cached;
return;
}
} catch (\Throwable $e) {
// Fall back to manual search on Redis error
}
}
$parts = explode('\\', $class);
$top = strtolower($parts[0] ?? '');
$relative = implode(DIRECTORY_SEPARATOR, array_slice($parts, 1));
@@ -59,9 +85,22 @@ spl_autoload_register(function (string $class): void {
// Try inside each module subfolder (e.g. customers\economicCustomers -> modules/economic/customers/economicCustomers.php)
static $module_dirs = null;
if ($module_dirs === null) {
$module_dirs = array_filter(scandir($base . 'modules'), function($item) use ($base) {
return $item !== '.' && $item !== '..' && is_dir($base . 'modules' . DIRECTORY_SEPARATOR . $item);
});
if (defined('redis')) {
try {
$module_dirs = redis->get_array('autoload:module_dirs');
} catch (\Throwable $e) {}
}
if ($module_dirs === null) {
$module_dirs = array_filter(scandir($base . 'modules'), function($item) use ($base) {
return $item !== '.' && $item !== '..' && is_dir($base . 'modules' . DIRECTORY_SEPARATOR . $item);
});
if (defined('redis')) {
try {
redis->set_array('autoload:module_dirs', $module_dirs);
redis->expire('autoload:module_dirs', 3600); // Cache for 1 hour
} catch (\Throwable $e) {}
}
}
}
foreach ($module_dirs as $mod) {
$candidates[] = $base . 'modules' . DIRECTORY_SEPARATOR . $mod . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class);
@@ -76,6 +115,11 @@ spl_autoload_register(function (string $class): void {
if (is_file($file)) {
require_once $file;
if (class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false) || (function_exists('enum_exists') && enum_exists($class, false))) {
if (defined('redis')) {
try {
redis->setEx('autoload:' . $class, $file, 86400); // Cache for 24 hours
} catch (\Throwable $e) {}
}
return;
}
}
@@ -94,10 +138,14 @@ $router = new router();
$response = new response();
$request = new request();
$db = new db($CONFIG_DB);
try {
define("redis", (new redis())->connect());
} catch (Exception $e) {
$response->error($e->getMessage(), 500);
// Ensure Redis is connected
if (!defined('redis')) {
try {
define("redis", (new redis())->connect());
} catch (Exception $e) {
$response->error($e->getMessage(), 500);
}
}
// Connect to the database, and ensure the connection is successful