build array in auto_loader constructor (#7158)

* Build an array in the auto_loader constructor

* Update auto_loader.php

* Update auto_loader.php

* minor adjustment to name and comment and remove trailing closing tag

* use best practices for the loader method
Allowing the loader method:
- Should Never Be Called Manually
- Prevents External Modification
- Hides Implementation Details

* cache array in the temp folder and load if available

* re-organize functions within the class

* add cache recreation for auto_loader in upgrade_menu

* add cache recreation for auto_loader in upgrade_menu

* Update app_languages.php
This commit is contained in:
frytimo
2025-02-13 17:48:40 -04:00
committed by GitHub
parent 9b0eead911
commit 0931197137
3 changed files with 265 additions and 69 deletions

View File

@@ -26,27 +26,85 @@
class auto_loader {
public function __construct() {
const FILE = 'autoloader_cache.php';
private $classes;
public function __construct($project_path = '') {
//classes must be loaded before this object is registered
if (!$this->load_cache()) {
$this->reload_classes($project_path);
}
//register this object to load any unknown classes
spl_autoload_register(array($this, 'loader'));
}
public static function autoload_search($array) : string {
if (!is_array($array) && count($path) != 0) {
return '';
public function update_cache(string $file = ''): bool {
//ensure we have somewhere to put the file
if (empty($file)) {
$file = sys_get_temp_dir() . '/' . self::FILE;
}
foreach($array as $path) {
if (is_array($path) && count($path) != 0) {
foreach($path as $sub_path) {
if (!empty($sub_path) && file_exists($sub_path)) {
return $sub_path;
}
}
//guard against writing an empty file
if (!empty($this->classes)) {
//export the classes array using PHP engine
$data = var_export($this->classes, true);
//put the array in a form that it can be loaded directly to an array
$result = file_put_contents($file, "<?php\n return " . $data . ";\n");
if ($result !== false) {
return true;
}
elseif (!empty($path) && file_exists($path)) {
return $path;
$error_array = error_get_last();
//send to syslog when debugging
if (!empty($_REQUEST['debug']) && $_REQUEST['debug'] == 'true') {
openlog("PHP", LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_WARNING, "[php][auto_loader] " . $error_array['message']);
closelog();
}
}
return '';
return false;
}
public function load_cache(string $file = ''): bool {
$this->classes = [];
//use a standard file
if (empty($file)) {
$file = sys_get_temp_dir() . '/'. self::FILE;
}
//use PHP engine to parse it
if (file_exists($file)) {
$this->classes = include $file;
}
//assign to an array
if (!empty($this->classes)) {
return true;
}
return false;
}
public function reload_classes($project_path = '') {
//set project path using magic dir constant
if (empty($project_path)) {
$project_path = dirname(__DIR__, 2);
}
//build the array of all classes
$search_path = [];
$search_path = array_merge($search_path, glob($project_path . '/resources/classes/*.php'));
$search_path = array_merge($search_path, glob($project_path . '/resources/interfaces/*.php'));
$search_path = array_merge($search_path, glob($project_path . '/resources/traits/*.php'));
$search_path = array_merge($search_path, glob($project_path . '/*/*/resources/classes/*.php'));
$search_path = array_merge($search_path, glob($project_path . '/*/*/resources/interfaces/*.php'));
$search_path = array_merge($search_path, glob($project_path . '/*/*/resources/traits/*.php'));
//reset the current array
$this->classes = [];
//store the class name (key) and the path (value)
foreach ($search_path as $path) {
$this->classes[basename($path, '.php')] = $path;
}
}
private function loader($class_name) : bool {
@@ -54,40 +112,23 @@ class auto_loader {
//sanitize the class name
$class_name = preg_replace('[^a-zA-Z0-9_]', '', $class_name);
//use glob for a more extensive search for the classes (note: GLOB_BRACE doesn't work on some systems)
if (!class_exists($class_name)) {
//set project path using magic dir constant
$project_path = dirname(__DIR__, 2);
//find the path using the class_name as the key in the classes array
if (isset($this->classes[$class_name])) {
//include the class or interface
include_once $this->classes[$class_name];
//build the search path array
$search_path[] = glob($project_path . "/resources/classes/".$class_name.".php");
$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");
$search_path[] = glob($project_path . "/*/*/resources/interfaces/".$class_name.".php");
$search_path[] = glob($project_path . "/*/*/resources/traits/".$class_name.".php");
//return boolean
return true;
}
//find the path
$path = self::autoload_search($search_path);
if (!empty($path)) {
//send to syslog
if (!empty($_REQUEST['debug']) && $_REQUEST['debug'] == 'true') {
openlog("PHP", LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_WARNING, "[php][autoloader] name: ".$class_name.", path: ".$path.", line: ".__line__);
closelog();
}
//include the class or interface
include $path;
//return boolean
return true;
}
//send to syslog when debugging
if (!empty($_REQUEST['debug']) && $_REQUEST['debug'] == 'true') {
openlog("PHP", LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_WARNING, "[php][auto_loader] class not found name: ".$class_name);
closelog();
}
//return boolean
return false;
}
}
?>