mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2026-03-16 05:22:11 +00:00
Remove file caching in auto loader (#7752)
This commit is contained in:
@@ -35,21 +35,7 @@
|
||||
class auto_loader {
|
||||
|
||||
const CLASSES_KEY = 'autoloader_classes';
|
||||
const CLASSES_FILE = 'autoloader_cache.php';
|
||||
const INTERFACES_KEY = "autoloader_interfaces";
|
||||
const INTERFACES_FILE = "autoloader_interface_cache.php";
|
||||
/**
|
||||
* Cache path and file name for classes
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $classes_file = null;
|
||||
/**
|
||||
* Cache path and file name for interfaces
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $interfaces_file = null;
|
||||
private $classes;
|
||||
/**
|
||||
* Tracks the APCu extension for caching to RAM drive across requests
|
||||
@@ -64,6 +50,7 @@ class auto_loader {
|
||||
*/
|
||||
private $interfaces;
|
||||
/**
|
||||
* Stores trait definitions (currently unused but kept for future expansion)
|
||||
* @var array
|
||||
*/
|
||||
private $traits;
|
||||
@@ -78,16 +65,6 @@ class auto_loader {
|
||||
//set if we can use RAM cache
|
||||
$this->apcu_enabled = function_exists('apcu_enabled') && apcu_enabled();
|
||||
|
||||
//set classes cache location
|
||||
if (empty(self::$classes_file)) {
|
||||
self::$classes_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::CLASSES_FILE;
|
||||
}
|
||||
|
||||
//set interface cache location
|
||||
if (empty(self::$interfaces_file)) {
|
||||
self::$interfaces_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::INTERFACES_FILE;
|
||||
}
|
||||
|
||||
//classes must be loaded before this object is registered
|
||||
if ($disable_cache || !$this->load_cache()) {
|
||||
//cache miss so load them
|
||||
@@ -100,42 +77,35 @@ class auto_loader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the class cache from various sources.
|
||||
* Loads the class cache from APCu if available.
|
||||
*
|
||||
* @return bool True if the cache is loaded successfully, false otherwise.
|
||||
*/
|
||||
public function load_cache(): bool {
|
||||
$this->classes = [];
|
||||
$this->interfaces = [];
|
||||
$this->traits = [];
|
||||
$this->traits = []; // Reset traits array
|
||||
|
||||
//use apcu when available
|
||||
if ($this->apcu_enabled && apcu_exists(self::CLASSES_KEY)) {
|
||||
//use apcu when available - validate BOTH keys exist
|
||||
if ($this->apcu_enabled && apcu_exists(self::CLASSES_KEY) && apcu_exists(self::INTERFACES_KEY)) {
|
||||
$this->classes = apcu_fetch(self::CLASSES_KEY, $classes_cached);
|
||||
$this->interfaces = apcu_fetch(self::INTERFACES_KEY, $interfaces_cached);
|
||||
//don't use files when we are using apcu caching
|
||||
if ($classes_cached && $interfaces_cached)
|
||||
|
||||
//validate fetched data is arrays and not corrupted
|
||||
if ($classes_cached && $interfaces_cached &&
|
||||
is_array($this->classes) && is_array($this->interfaces) &&
|
||||
!empty($this->classes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//log when cache validation fails
|
||||
if ($classes_cached || $interfaces_cached) {
|
||||
self::log(LOG_WARNING, "APCu cache validation failed - classes_cached: " . ($classes_cached ? 'true' : 'false') . ", interfaces_cached: " . ($interfaces_cached ? 'true' : 'false') . ", is_array(classes): " . (is_array($this->classes) ? 'true' : 'false') . ", is_array(interfaces): " . (is_array($this->interfaces) ? 'true' : 'false'));
|
||||
}
|
||||
}
|
||||
|
||||
//use PHP engine to parse it
|
||||
if (file_exists(self::$classes_file)) {
|
||||
$this->classes = include self::$classes_file;
|
||||
}
|
||||
|
||||
//do the same for interface to class mappings
|
||||
if (file_exists(self::$interfaces_file)) {
|
||||
$this->interfaces = include self::$interfaces_file;
|
||||
}
|
||||
|
||||
//catch edge case of first time using apcu cache
|
||||
if ($this->apcu_enabled) {
|
||||
apcu_store(self::CLASSES_KEY, $this->classes);
|
||||
apcu_store(self::INTERFACES_KEY, $this->interfaces);
|
||||
}
|
||||
|
||||
//return true when we have classes and false if the array is still empty
|
||||
return (!empty($this->classes) && !empty($this->interfaces));
|
||||
//return false when we don't have classes in memory
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,9 +138,6 @@ class auto_loader {
|
||||
$files = array_merge($files, glob($path));
|
||||
}
|
||||
|
||||
//reset the current array
|
||||
$class_list = [];
|
||||
|
||||
//store the class name (key) and the path (value)
|
||||
foreach ($files as $file) {
|
||||
$file_content = file_get_contents($file);
|
||||
@@ -246,50 +213,46 @@ class auto_loader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cache by writing the classes and interfaces to files on disk.
|
||||
* Updates the cache by storing classes and interfaces in APCu if available.
|
||||
*
|
||||
* @return bool True if the update was successful, false otherwise
|
||||
*/
|
||||
public function update_cache(): bool {
|
||||
//guard against writing an empty file
|
||||
//guard against empty cache
|
||||
if (empty($this->classes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//update RAM cache when available
|
||||
//update APCu cache when available
|
||||
if ($this->apcu_enabled) {
|
||||
$classes_cached = apcu_store(self::CLASSES_KEY, $this->classes);
|
||||
$interfaces_cached = apcu_store(self::INTERFACES_KEY, $this->interfaces);
|
||||
//do not save to drive when we are using apcu
|
||||
if ($classes_cached && $interfaces_cached)
|
||||
$classes_stored = apcu_store(self::CLASSES_KEY, $this->classes, 0);
|
||||
$interfaces_stored = apcu_store(self::INTERFACES_KEY, $this->interfaces, 0);
|
||||
|
||||
//log failures to help diagnose APCu issues
|
||||
if (!$classes_stored) {
|
||||
self::log(LOG_WARNING, "Failed to store classes to APCu");
|
||||
}
|
||||
if (!$interfaces_stored) {
|
||||
self::log(LOG_WARNING, "Failed to store interfaces to APCu");
|
||||
}
|
||||
|
||||
//both must succeed for consistency
|
||||
if ($classes_stored && $interfaces_stored) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//if one failed, clear APCu to prevent inconsistent state
|
||||
if ($classes_stored || $interfaces_stored) {
|
||||
apcu_delete(self::CLASSES_KEY);
|
||||
apcu_delete(self::INTERFACES_KEY);
|
||||
self::log(LOG_WARNING, "Cleared APCu cache due to partial store failure");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//export the classes array using PHP engine
|
||||
$classes_array = var_export($this->classes, true);
|
||||
|
||||
//put the array in a form that it can be loaded directly to an array
|
||||
$class_result = file_put_contents(self::$classes_file, "<?php\n return " . $classes_array . ";\n");
|
||||
if ($class_result === false) {
|
||||
//file failed to save - send error to syslog when debugging
|
||||
$error_array = error_get_last();
|
||||
self::log(LOG_WARNING, $error_array['message'] ?? '');
|
||||
}
|
||||
|
||||
//export the interfaces array using PHP engine
|
||||
$interfaces_array = var_export($this->interfaces, true);
|
||||
|
||||
//put the array in a form that it can be loaded directly to an array
|
||||
$interface_result = file_put_contents(self::$interfaces_file, "<?php\n return " . $interfaces_array . ";\n");
|
||||
if ($interface_result === false) {
|
||||
//file failed to save - send error to syslog when debugging
|
||||
$error_array = error_get_last();
|
||||
self::log(LOG_WARNING, $error_array['message'] ?? '');
|
||||
}
|
||||
|
||||
$result = ($class_result && $interface_result);
|
||||
|
||||
return $result;
|
||||
//APCu not available, cache remains in memory only
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,48 +284,17 @@ class auto_loader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cache of stored classes and interfaces.
|
||||
* Clears the cache of stored classes and interfaces from APCu.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear_cache() {
|
||||
|
||||
//check for apcu cache
|
||||
//check for apcu cache and clear it
|
||||
if (function_exists('apcu_enabled') && apcu_enabled()) {
|
||||
apcu_delete(self::CLASSES_KEY);
|
||||
apcu_delete(self::INTERFACES_KEY);
|
||||
}
|
||||
|
||||
//set default file
|
||||
if (empty(self::$classes_file)) {
|
||||
self::$classes_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::CLASSES_FILE;
|
||||
}
|
||||
|
||||
//set file to clear
|
||||
$classes_file = self::$classes_file;
|
||||
|
||||
//remove the file when it exists
|
||||
if (file_exists($classes_file)) {
|
||||
@unlink($classes_file);
|
||||
$error_array = error_get_last();
|
||||
//send to syslog when debugging with either environment variable or debug in the url
|
||||
self::log(LOG_WARNING, $error_array['message'] ?? '');
|
||||
}
|
||||
|
||||
if (empty(self::$interfaces_file)) {
|
||||
self::$interfaces_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::INTERFACES_FILE;
|
||||
}
|
||||
|
||||
//set interfaces file to clear
|
||||
$interfaces_file = self::$interfaces_file;
|
||||
|
||||
//remove the file when it exists
|
||||
if (file_exists($interfaces_file)) {
|
||||
@unlink($interfaces_file);
|
||||
$error_array = error_get_last();
|
||||
//send to syslog when debugging with either environment variable or debug in the url
|
||||
self::log(LOG_WARNING, $error_array['message'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,7 +365,7 @@ class auto_loader {
|
||||
private function loader($class_name): bool {
|
||||
|
||||
//sanitize the class name
|
||||
$class_name = preg_replace('[^a-zA-Z0-9_]', '', $class_name);
|
||||
$class_name = preg_replace('/[^a-zA-Z0-9_]/', '', $class_name);
|
||||
|
||||
//find the path using the class_name as the key in the classes array
|
||||
if (isset($this->classes[$class_name])) {
|
||||
@@ -471,6 +403,7 @@ class auto_loader {
|
||||
$project_path = dirname(__DIR__, 2);
|
||||
|
||||
//build the search path array
|
||||
$search_path = [];
|
||||
$search_path[] = glob($project_path . "/resources/interfaces/" . $class_name . ".php");
|
||||
$search_path[] = glob($project_path . "/resources/traits/" . $class_name . ".php");
|
||||
$search_path[] = glob($project_path . "/resources/classes/" . $class_name . ".php");
|
||||
|
||||
Reference in New Issue
Block a user