如何在PHP中为多个目录使用spl_自动加载_寄存器?

如何在PHP中为多个目录使用spl_自动加载_寄存器?,php,spl-autoload-register,Php,Spl Autoload Register,实际上,我正在尝试为自己创建一个MVC框架,但是我在自动加载方面遇到了问题。实际上这不是问题,但我想问一下专家,当存在不同的目录时,他们是如何使用spl\u autoload\u register功能的 假设我们有以下目录: Controllers Libs Models 每个文件夹包含不同的类,如: Controllers: Main.php File.php About.php Libs: Main.php Front_controller.php Model

实际上,我正在尝试为自己创建一个MVC框架,但是我在自动加载方面遇到了问题。实际上这不是问题,但我想问一下专家,当存在不同的目录时,他们是如何使用
spl\u autoload\u register
功能的

假设我们有以下目录:

Controllers
Libs
Models
每个文件夹包含不同的类,如:

Controllers:
   Main.php
   File.php
   About.php
Libs:
   Main.php
   Front_controller.php
Models:
   Index.php
   File.php
   Login.php
您可以注意到,在不同的目录中可能会找到一些同名的文件名。好的,到目前为止我已经试过了:

spl_autoload_register(function ($class) { 

    $pathContorllers = 'Controllers/' . $class . '.php';
    $pathLibs = 'Libs/' . $class . '.php';
    $pathModels = 'Models/' . $class . '.php';

    if (file_exists($pathContorllers)) {
        require_once $pathContorllers;
    } elseif (file_exists($pathLibs)) {
        require_once $pathLibs;
    } elseif (file_exists($pathModels )) {
        require_once $pathModels ;
    }
});
它工作得很好,但是我相信还有另一种方法可以让一切变得更简单。有谁能建议我如何使这段代码更好或更简单/在这种情况下,大师们在使用什么

为了防止可能遇到此答案的个人获取过期信息,我已根据最新PSR自动加载标准对其进行了更新。出于历史目的和仅对PSR-0自动装弹机感兴趣的人,保留了原始答案

spl_autoload_register( function ($className) {
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
});

//Now you can make your call to your objects without a bunch of include/require statements

$main = new \MyProject\Controllers\Main();  //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login();   //Instantiates your 'Login' model
最新答案 官方反对该标准,支持替代自动加载器。虽然两者在某些方面相似,但在其他方面也有很大不同。(例如:类名称中下划线的处理。)

你可能在想——“我现在使用PSR-0,它工作得很好。”事实是,PSR-0在某些项目上仍然工作得很好。当涉及到与不使用名称空间的包的向后兼容性时,尤其如此。PSR-0仍然是一个不错的自动加载原则,但它可以

当然,如果编程中有一件事是不变的,那就是代码最终会发生变化,编程技术也会不断发展。今天你可以帮自己一个忙,为明天做好准备。因此,如果您正在启动项目或试图将项目移植到可以使用命名空间的PHP的新版本,则应该认真考虑使用PSR4自动加载程序。

spl_autoload_register( function ($className) {
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
});

//Now you can make your call to your objects without a bunch of include/require statements

$main = new \MyProject\Controllers\Main();  //Instantiates your 'Main' controller
$login = new \MyProject\Models\Login();   //Instantiates your 'Login' model
另外值得注意的是,如果您正在开发一个不使用名称空间的项目,那么PSR-4不适用于您。在这种情况下,PSR-0或您自己的自定义自动加载器适用


原始答案 如果您想在类中使用名称空间,那么路由是一种非常好的自动加载方式。基本上,名称空间表示目录结构,可以根据约定加载类

如果PSR-0方法不能满足您的所有需求(或者不能很好地处理现有代码),您仍然可以使用
spl\u autoload\u register
添加更多函数,PHP将逐一检查这些函数,以尝试加载类

用法示例:

首先,如果您不熟悉PHP,那么您将从PHP手册中获益。一开始它们可能有点混乱,但它们的好处值得最初的混乱

所以我说PSR-0的工作原理是将名称空间与目录结构相关联。让我们以您的目录为例。您的根文件夹(无论在何处)中包含以下内容:

Project directory:  <- Let's call this directory "MyProject"
    Controllers:
       Main.php
       File.php
       About.php
    Libs:
       Main.php
       Front_controller.php
    Models:
       Index.php
       File.php
       Login.php
index.php <- Let's say this is your entry point file, this is where you will be autoloading stuff from.
对于您的
登录
型号,您也会做同样的事情

<?php

namespace MyProject\Models;

class Login {

    //Field vars, contructor, methods, etc. all go here.
    
}

?>

希望这有助于更好地理解它,同样,如果您不想使用名称空间,您可以始终将闭包添加到SPL自动加载堆栈中。如果需要,您可以在其中安装10个不同的自动加载器,PHP将使用每个函数逐个(按照您定义的顺序)检查它们,以尝试加载一个类。然而,一对夫妇的公约为基础的自动加载器是一个有点干净,更喜欢的方法。还要记住,自动加载程序将名称空间分隔符
\
和下划线
\
转换为目录分隔符。因此,您的
Front\u controller.php不会像您预期的那样自动加载。

下面的代码会有所帮助。但我建议你检查名称空间

spl_autoload_register ( function ($class) {

$sources = array("Controllers/$class.php", "Lib/$class.php ",  "Models/$class.php " );

    foreach ($sources as $source) {
        if (file_exists($source)) {
            require_once $source;
        } 
    } 
});

这个问题已经在这里解决了。我已经看过了,但是我真的不知道应该如何实现示例代码。这对我来说并不是很明显。我已经更新了我的答案,以便更好地解释它。希望这对您有所帮助。@Crackertastic-感谢您提供了这个极好的示例。在对这个概念的修改中,我发现有必要修改类文件中的名称空间。例如,而不是
名称空间MyProject\Models,它不起作用,
名称空间模型确实有用。@knot22很高兴听到这个(旧的)示例仍在帮助其他人。快乐编码!不赞成。