如何在PHP中对多个区使用spl_autoload_register? [英] How to use spl_autoload_register for multiple diectories in PHP?

查看:95
本文介绍了如何在PHP中对多个区使用spl_autoload_register?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实际上是想为自己创建一个MVC框架,但是我在使用Autoload时遇到了麻烦.实际上这不是问题,但是我想问问大师,当目录不同时,他们如何使用spl_autoload_register函数.

I'm actually trying to create a MVC framework for my own, however I'm having troubles with the Autoload. It's not a problem actually, but I'd like to ask the gurus, how are they using the spl_autoload_register function when there are different directories.

可以说我们有以下目录:

Lets say we have the following directories:

Controllers
Libs
Models

每个文件夹包含不同的类,例如:

Each folder contains different classes, like:

Controllers:
   Main.php
   File.php
   About.php
Libs:
   Main.php
   Front_controller.php
Models:
   Index.php
   File.php
   Login.php

您会注意到,在不同目录中可能会找到一些具有相同名称的文件名.好的,这就是我到目前为止尝试过的:

You can notice that some file names might be found with the same name in different directories. Okay, so this is what I've tried so far:

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 ;
    }
});

它运行良好,但是我敢肯定,还有另一种方法可以使一切变得更简单.谁能建议我如何使这段代码更好或更简单/在这种情况下大师使用什么?

It is working well, however I'm sure that there is another way to make everything simpler. Can anyone suggest me how can I make this code better or simpler / what are gurus using in this situation?

推荐答案

为了使可能会遇到此问题的个人免于获取过时的信息,我已针对最新的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 已正式弃用

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.

这篇关于如何在PHP中对多个区使用spl_autoload_register?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆