且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在PHP中对多个区使用spl_autoload_register?

更新时间:2023-11-17 08:10:10

为了使可能会遇到此问题的个人免于获取过时的信息,我已针对最新的PSR自动加载标准对其进行了更新.保留原始答案是出于历史目的,以及仅对PSR-0自动装带机感兴趣的人.

For the purpose of keeping individuals who may come across this answer from obtaining out-of-date information I have updated it in regards to the latest PSR autoloading standards. The original answer has been maintained for historical purposes and for those who are only interested in the PSR-0 autoloader.

更新的答案

PHP-FIG 已正式弃用 PSR-4 .尽管两者在某些方面相似,但在其他方面也有很大不同. (例如:对类名中的下划线的处理.)

Updated Answer

The PHP-FIG has officially deprecated the PSR-0 standard in favor of the alternative autoloader, PSR-4. Although the two are similar in some aspects they are also very different in others. (E.g.: the handling of underscores in class names.)

您可能正在想自己-我现在使用PSR-0,它可以正常工作." 事实的真相是,PSR-0在某些项目中仍然可以正常工作.当涉及到与不使用名称空间的包的向后兼容性时,尤其如此. PSR-0仍然是一种不错的自动加载原理,但它具有其功能自己的缺点.

You may be thinking to yourself -- "I use PSR-0 now and it works fine." The truth of the matter is that PSR-0 will still work fine for certain projects. This is especially true when backwards compatibility with a package that doesn't use namespaces is concerned. PSR-0 is still a decent autoloading principle, but it has its own shortcomings.

当然,如果编程中有一件事是不变的,那就是代码最终会改变,而编程技术也在不断发展.今天就做好准备,可以为明天做点事.因此,如果您只是开始一个项目或试图将一个项目移植到可以使用名称空间的PHP的较新版本,则应认真考虑使用PSR-4自动加载器.

Of course, if there is one thing that is a constant with programming, it is that code eventually changes and programming techniques continue to evolve. You can do yourself a favor today by preparing yourself for tomorrow. Therefore, if you are just starting a project or are trying to port a project to a newer version of PHP that can use namespaces, you should seriously consider using the PSR-4 autoloader.

还值得注意的是,如果您开发的项目不使用名称空间,则PSR-4不适用于您.在这种情况下,将应用PSR-0或您自己的自定义自动加载器.

It is also worth noting that if you are developing a project that does not use namespaces then PSR-4 does not apply to you. In this case PSR-0 or your own custom autoloader applies.

如果要在类中使用命名空间,则 PSR-0 路由是一种自动加载的好方法.基本上,您的名称空间代表您的目录结构,并且可以根据约定加载类.

If you want to go with namespaces in your classes, then the PSR-0 route is a pretty good way to autoload. Basically your namespace represents you directory structure and classes can be loaded based on a convention.

如果PSR-0方法不能满足您的所有需求(或不能很好地与现有代码配合使用),您仍然可以使用spl_autoload_register添加更多功能,PHP会逐一处理这些功能,以尝试加载类.

If the PSR-0 method doesn't meet all your needs (or doesn't play nice with existing code) you can still add more functions with spl_autoload_register and PHP will go through them one by one in an attempt to load classes.

用法示例:

首先是第一件事,如果您不熟悉PHP中的命名空间,那么您将受益于签出有关该主题的PHP手册.一开始它们可能会有些混乱,但是它们的好处值得一开始的困惑.

First thing is first, if you aren't familiar with namespaces in PHP then you will benefit from checking out the PHP manual on the subject. They can be a bit confusing at first, but their benefits are worth the initial confusion.

因此,我说过PSR-0的工作原理是将名称空间与目录结构相关联.让我们以您的目录为例.您的根文件夹(无论位于哪里)中都包含以下内容:

So I said that PSR-0 works by associating your namespaces with your directory structure. Let's use your directories for an example. You have in your root folder (wherever it may be) the following:

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.

现在让我们来看看您的控制器Main.php.需要牢记的两件事是,类名必须是文件名,而该类的名称空间是该文件的目录路径.所以Main.php应该看起来像这样:

Now let's take a look at your controller Main.php. Two things to keep in mind is that the class name needs to be the name of the file and the namespace for that class is the directory path to that file. So Main.php should look something like this:

<?php

namespace MyProject\Controllers;

class Main {

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

?>

对于您的Login模型,您将做同样的事情

You would do the same thing for your your Login model

<?php

namespace MyProject\Models;

class Login {

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

?>

现在在您的index.php文件中(在根目录-MyProject中),您将调用spl_autoload_register并将其赋予PSR-0自动加载器.

Now in your index.php file (out in the root directory - MyProject) you would make your call to the spl_autoload_register and give it the PSR-0 autoloader.

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

希望这有助于更好地理解它,再次,如果您不想使用名称空间,则始终可以始终将闭包添加到SPL自动加载堆栈中.如果需要,您可以在其中有10个不同的自动加载器,PHP会使用每个函数尝试一次加载一个类,并按定义的顺序逐个通过它们.但是,基于几个约定的自动装带器更干净一些,更是一种首选方法.还请记住,自动加载器会将名称空间分隔符\和下划线_都转换为目录分隔符.因此,您的Front_controller.php不会像您期望的那样自动加载.

Hopefully that helps make better sense of it, and again, if you don't want to use namespaces you can always just keep adding closures into the SPL autoload stack. You can have 10 different autoloaders in there if you want and PHP will go through them one by one (in the order you defined them) using each function to try and load a class. However, a couple convention based autoloaders is a bit cleaner and more of a preferred method. Also keep in mind that the autoloader translates both namespace separators \ and underscores _ as a directory separator. So your Front_controller.php would not autoload as you would expect.