PHP - 只需要自动加载 类

PHP - Autoload only needed classes

我有一个自动加载器,作为 php 文件放置在我项目中所有其他子目录的上方。

它的作用是为任何特定的服务器请求一次加载所有可能的 classes。经过进一步思考,我得出结论,我只需要自动加载所需的 classes.

我需要做什么来避免加载其他 class 不需要的内容?
如果我需要 post 子目录中 class 文件的相关代码片段,我可以。

<?php
    namespace autoloader;
    class autoloader
    {
        private $directoryName;
        
        public function __construct($directoryName)  
        {
            $this->directoryName = $directoryName;
        }  
        
        public function autoload()
        {
            foreach (glob("{$this->directoryName}/*.class.php") as $filename)
            {
                include_once $filename;           
            }
         
            foreach (glob("{$this->directoryName}/*.php") as $filename)
            {
                include_once $filename;           
            }
        }    
    }
    
    # nullify any existing autoloads
    spl_autoload_register(null, false);

    # instantiate the autoloader object
    $classes = [
        new autoloader('request'),
        new autoloader('config'),
        new autoloader('controllers'), 
        new autoloader('models'),
        new autoloader('data')
    ];

    # register the loader functions
    foreach ($classes as $class)
        spl_autoload_register(array($class, 'autoload'));

当您尝试实例化一个新的 class 或直到它最终加载 class 或抛出错误时,将调用所有已注册的自动加载器函数。按照您现在的方式,您正在为每个目录和文件一次又一次地注册相同的自动加载器功能。

您想要做的是与此类似的事情。

namespace autoloader;

class autoloader
{
    public function __construct()
    {
        spl_autoload_register([$this, 'autoload']);
    }

    public function autoload($classname)
    {
        if (! file_exists("{$classname}.class.php")) {
            return;
        }

        include_once "{$classname}.class.php";
    }    
}

new autoloader();

每个自动加载器函数都会将 class FQCN 传递给它,然后您必须从那里解析它并确定是否可以加载 class 存在的文件。例如,如果我执行以下操作。

use Some\Awesome\ClassFile;

$class = new ClassFile();

我们注册的自动加载器将获取作为参数传入的字符串 Some\Awesome\ClassFile,然后我们可以对其进行解析并查看是否有对应 class 的文件,如果没有的话t 我们 return 退出函数并让下一个注册的自动加载器函数尝试找到 class.

您可以在 documentation, I also wrote a blog post 中阅读更多关于自动加载器的信息,就像 2 个月前您可能感兴趣的那样。

我不得不重构代码并删除不必要的加载所有我错误地认为会根据请求延迟加载我的 类 的功能。

这是我想出的:

入口点

<?php
    require_once 'enums.php';
    require_once 'api.class.php';

    spl_autoload('AutoLoader\AutoLoader');
    
    use App\API;

    class MyAPI extends API
    { 
        public function __construct($request){
            parent::__construct($request);
        }
    }
    
    $api = new MyAPI($_REQUEST); 
    echo $api->processRequest();

AutoLoader 实现(位于子目录 Autoloader/Autoloader.php 下,无法使用 .htaccess 通过浏览器访问)

<?php
    namespace Autoloader;

    spl_autoload_register("AutoLoader\AutoLoader::ClassLoader");
    spl_autoload_register("AutoLoader\AutoLoader::RequestLoader");

    class Autoloader
    {
        public static function ClassLoader(String $fileName)
        {
            foreach ([".Class.php", ".php"] as $extension) 
                if (file_exists($fileName.$extension))
                    include $fileName.$extension;       
        } 
        
        public static function RequestLoader()
        {
            self::ClassLoader('Request');
        }
    }

processRequest() 的片段(位于 api.class.php - 我的请求路由器)

public function processRequest() 
{
    $id1 = $this->requestObj->id1;
    $id2 = $this->requestObj->id2;
    $endpoint1 = $this->requestObj->endpoint1;
    $endpoint2 = $this->requestObj->endpoint2;
    $goto = $this->requestObj->goto;

    $isDestination = in_array($id1, ['first', 'prev', 'next', 'last']);
    $numSetEndpoints = (int)isset($endpoint1) + (int)isset($endpoint2);
    
    switch($numSetEndpoints)
    {
        case 0:
            if ($isDestination)
                return json_decode($this->_response("No Endpoint: ", $endpoint1));
            return json_decode($this->_response("No Endpoint: " . $endpoint2 ?? $endpoint));
        case 1:
            $className = $endpoint1.'Controller';
            break;
        case 2:
            $className = $endpoint2.'Controller';
            break;
    }

    $class = "\Controllers\$className";

    if (class_exists($class))
    {
        $method = strtolower($this->method); 
        if (method_exists($class, $method))
        {
            $response = (new $class($this->requestObj))->{$method}();
            
            if ($response['Succeeded'] == false)
            {
                return $response['Result'];
            }
            else if ($response['Succeeded'] == true)
            {    
                header("Content-Type: application/json");
                return $this->_response($response);
            }
            else if ($response['Result'])
            {
                header("Content-Type: text/html");
                return $this->_response($response);
            } 
        }
    }
}