unregister(); } /** * Registers the autoload callback with the SPL autoload system. * * @since 1.0.0 */ public function register() { spl_autoload_register( [ $this, 'autoload' ] ); } /** * Unregisters the autoload callback with the SPL autoload system. * * @since 1.0.0 */ public function unregister() { spl_autoload_unregister( [ $this, 'autoload' ] ); } /** * Add a specific namespace structure with our custom autoloader. * * @since 1.0.0 * * @param string $root Root namespace name. * @param string $base_dir Directory containing the class files. * @param string $prefix Prefix to be added before the class. * @param string $suffix Suffix to be added after the class. * @param boolean $lowercase Whether the class should be changed to * lowercase. * @param boolean $underscores Whether the underscores should be changed to * hyphens. * @return self */ public function add_namespace( $root, $base_dir, $prefix = '', $suffix = '.php', $lowercase = false, $underscores = false ) { $this->namespaces[] = [ 'root' => $this->normalize_root( (string) $root ), 'base_dir' => trailingslashit( (string) $base_dir ), 'prefix' => (string) $prefix, 'suffix' => (string) $suffix, 'lowercase' => (bool) $lowercase, 'underscores' => (bool) $underscores, ]; usort($this->namespaces, function($a, $b) { return strlen($b['root']) - strlen($a['root']); }); return $this; } /** * The autoload function that gets registered with the SPL Autoloader * system. * * @since 1.0.0 * * @param string $class The class that got requested by the spl_autoloader. * @throws RuntimeException If the associated file is not readable in any registered namespace. */ public function autoload( $class ) { $class_found = false; $last_filepath = ''; // Iterate over namespaces to find a match. foreach ( $this->namespaces as $namespace ) { // Move on if the object does not belong to the current namespace. if ( 0 !== strpos( $class, $namespace['root'] ) ) { continue; } // Remove namespace root level to correspond with root filesystem. $filename = str_replace( $namespace['root'], '', $class ); // Replace the namespace separator "\" by the system-dependent // directory separator. $filename = str_replace( '\\', DIRECTORY_SEPARATOR, $filename ); // Remove a leading backslash from the class name. $filename = $this->remove_leading_backslash( $filename ); // Change to lower case if requested. if ( $namespace['lowercase'] ) { $filename = strtolower( $filename ); } // Change underscores into hyphens if requested. if ( $namespace['underscores'] ) { $filename = str_replace( '_', '-', $filename ); } // Add base_dir, prefix and suffix. $filepath = $namespace['base_dir'] . $namespace['prefix'] . $filename . $namespace['suffix']; $last_filepath = $filepath; // If file exists and is readable, load it and return if ( is_readable( $filepath ) ) { require( $filepath ); return; } // If file doesn't exist in the main directory, look for it in subdirectories $found_in_subfolder = $this->find_file_in_subdirectories( $namespace['base_dir'], $namespace['prefix'] . $filename . $namespace['suffix'] ); if ( $found_in_subfolder ) { require( $found_in_subfolder ); return; } // Otherwise continue checking other namespace paths } // If we've checked all namespaces and still can't find the file, throw exception if ( ! empty( $last_filepath ) ) { throw new RuntimeException( sprintf( 'Could not autoload class "%1$s", the corresponding file "%2$s" is not readable.', esc_html($class), esc_html($last_filepath) ) ); } } /** * Recursively search for a file in subdirectories * * @since 1.0.0 * * @param string $base_dir Base directory to start the search from * @param string $filename File name to look for * @return string|false Full path to the file if found, false otherwise */ protected function find_file_in_subdirectories( $base_dir, $filename ) { if ( ! is_dir( $base_dir ) ) { return false; } // First check if the file exists in this directory $full_path = $base_dir . $filename; if ( is_readable( $full_path ) ) { return $full_path; } // If not, check all subdirectories $dir_handle = opendir( $base_dir ); if ( $dir_handle ) { while ( ( $file = readdir( $dir_handle ) ) !== false ) { if ( $file === '.' || $file === '..' ) { continue; } $path = $base_dir . $file; if ( is_dir( $path ) ) { $path = trailingslashit( $path ); $found = $this->find_file_in_subdirectories( $path, $filename ); if ( $found ) { closedir( $dir_handle ); return $found; } } } closedir( $dir_handle ); } return false; } /** * Normalize a namespace root. * * @since 1.0.0 * * @param string $root Namespace root that needs to be normalized. * @return string Normalized namespace root. */ protected function normalize_root( $root ) { $root = $this->remove_leading_backslash( $root ); return $this->add_trailing_backslash( $root ); } /** * Remove a leading backslash from a string. * * @since 1.0.0 * * @param string $string String to remove the leading backslash from. * @return string Modified string. */ protected function remove_leading_backslash( $string ) { return ltrim( $string, '\\' ); } /** * Make sure a string ends with a trailing backslash. * * @since 1.0.0 * * @param string $string String to check the trailing backslash of. * @return string Modified string. */ protected function add_trailing_backslash( $string ) { return rtrim( $string, '\\' ) . '\\'; } } $auto_loader = new Autoloader(); $auto_loader->add_namespace( 'PISOL\\ANFW\\FRONT\\', PISOL_ANFW_FOLDER_PATH.'public/', 'class-', '.php', true, true ); $auto_loader->add_namespace( 'PISOL\\ANFW\\ADMIN\\', PISOL_ANFW_FOLDER_PATH.'admin/', 'class-', '.php', true, true ); // Add support for the Conditions namespace $auto_loader->add_namespace( 'PISOL\\ANFW\\ADMIN\\', PISOL_ANFW_FOLDER_PATH.'admin/conditions/', 'class-', '.php', true, true ); $auto_loader->register();