如何使用 __autoload 从多个目录加载类?

发布于 2024-12-09 10:42:49 字数 1777 浏览 0 评论 0 原文

跟进这个问题,似乎可以通过以下方式解决重复问题只是使用下面的 __autoload 代码,

function __autoload($class_name) 
{
    include AP_SITE."classes_1/class_".$class_name.".php";
}

$connection = new database_pdo(DSN,DB_USER,DB_PASS);
var_dump($connection);

结果,

object(database_pdo)[1]
  protected 'connection' => 
    object(PDO)[2]

但这只能从一个目录加载类,那么其他目录呢?因为我将类分组在不同的目录中。所以如果我想从其他目录加载类,

function __autoload($class_name) 
{
    include AP_SITE."classes_1/class_".$class_name.".php";
    include AP_SITE."classes_2/class_".$class_name.".php";
}

消息,

我会得到错误,

警告: 包括(C:/wamp/www/art_on_your_doorstep_2011_MVC/global/applications/CART/classes_2/class_database_pdo.php) [function.include]:无法打开流:没有这样的文件或目录 在...

引用了这一行 - include AP_SITE."classes_2/class_".$class_name.".php";

所以,我的问题是 - 如何使用 < 从多个目录加载类代码>__autoload

可能的解决方案:

function autoload_class_multiple_directory($class_name) 
{

    # List all the class directories in the array.
    $array_paths = array(
        'classes_1/', 
        'classes_2/'
    );

    # Count the total item in the array.
    $total_paths = count($array_paths);

    # Set the class file name.
    $file_name = 'class_'.strtolower($class_name).'.php';

    # Loop the array.
    for ($i = 0; $i < $total_paths; $i++) 
    {
        if(file_exists(AP_SITE.$array_paths[$i].$file_name)) 
        {
            include_once AP_SITE.$array_paths[$i].$file_name;
        } 
    }
}

spl_autoload_register('autoload_class_multiple_directory');

Following up on this question, it seems that the duplicate issue could be solved by just using the __autoload code below,

function __autoload($class_name) 
{
    include AP_SITE."classes_1/class_".$class_name.".php";
}

$connection = new database_pdo(DSN,DB_USER,DB_PASS);
var_dump($connection);

result,

object(database_pdo)[1]
  protected 'connection' => 
    object(PDO)[2]

but this only loads the classes from one directory, what about other directories? Because I group the classes in different directories. So I will get error if I want to load classes from other directories,

function __autoload($class_name) 
{
    include AP_SITE."classes_1/class_".$class_name.".php";
    include AP_SITE."classes_2/class_".$class_name.".php";
}

message,

Warning:
include(C:/wamp/www/art_on_your_doorstep_2011_MVC/global/applications/CART/classes_2/class_database_pdo.php)
[function.include]: failed to open stream: No such file or directory
in ...

which refers to this line - include AP_SITE."classes_2/class_".$class_name.".php";

So, my question is - how can I load classes from multiple directories with __autoload?

a possible solution:

function autoload_class_multiple_directory($class_name) 
{

    # List all the class directories in the array.
    $array_paths = array(
        'classes_1/', 
        'classes_2/'
    );

    # Count the total item in the array.
    $total_paths = count($array_paths);

    # Set the class file name.
    $file_name = 'class_'.strtolower($class_name).'.php';

    # Loop the array.
    for ($i = 0; $i < $total_paths; $i++) 
    {
        if(file_exists(AP_SITE.$array_paths[$i].$file_name)) 
        {
            include_once AP_SITE.$array_paths[$i].$file_name;
        } 
    }
}

spl_autoload_register('autoload_class_multiple_directory');

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幸福丶如此 2024-12-16 10:42:50

您可以使用 spl_autoload_register 注册多个自动加载函数,而不是使用单个 __autoload< /代码> 功能。这是推荐的方式。

如果一个自动加载器能够加载该文件,则不会调用堆栈中的下一个自动加载器。

然而,每个自动加载器应该只加载它所属的类,因此您需要通过类名和/或使用 is_file 进行检查。按类名通常更好,因为如果应用程序增长,在文件系统上疯狂尝试会给系统带来压力。

为了不重新发明轮子,您甚至可以使用已经存在的自动加载器,它能够处理文件名调用的 PSR-0 标准。这些通常允许在基本目录上注册特定的名称空间。在您的情况下,这意味着您必须根据 PSR-0 约定


快速解决方案(与您的问题相关):

function __autoload($class_name) 
{
    $file = sprintf('%sclasses_1/class_%s.php', AP_SITE, $class_name);
    if (is_file($file))
    {
        include $file;
        return;
    }
    $file = sprintf('%sclasses_2/class_%s.php', AP_SITE, $class_name);
    if (is_file($file))
    {
        include $file;
        return;
    }
}

如您所见,已经有代码重复(如您的代码所示)。因此,这应该只是一个临时解决方案,因为对于您想要测试的每个目录,您最终会得到越来越多的重复行。如果您考虑更改设计,请考虑 PSR-0 模式,它有助于简化代码库,并使重用 PHP 世界中的其他现有组件变得容易。


function autoload_class_multiple_directory($class_name) 
{

    # List all the class directories in the array.
    $array_paths = array(
        'classes_1/', 
        'classes_2/'
    );

    foreach($array_paths as $path)
    {
        $file = sprintf('%s%s/class_%s.php', AP_SITE, $path, $class_name);
        if(is_file($file)) 
        {
            include_once $file;
        } 

    }
}

spl_autoload_register('autoload_class_multiple_directory');

You can register multiple autoload functions by using spl_autoload_register instead of the single __autoload function. That's the recommended way.

If one autoloader was able to load the file, the next one in the stack won't be called.

Each autoloader however should only load the classes it is for, so you need to check that by the classname and/or with is_file. By classname often is better because trying wildly on the file-system can stress a system if your application grows.

To not re-invent the wheel, you could even use an autoloader that already exists which is able to deal with the PSR-0 standard on file-name-calling. Those often allow to register a specific namespace on a base-directory. In your case that would mean that you must rename and organize your files according to the PSR-0 convention.


The quick solution (bound to your question):

function __autoload($class_name) 
{
    $file = sprintf('%sclasses_1/class_%s.php', AP_SITE, $class_name);
    if (is_file($file))
    {
        include $file;
        return;
    }
    $file = sprintf('%sclasses_2/class_%s.php', AP_SITE, $class_name);
    if (is_file($file))
    {
        include $file;
        return;
    }
}

As you can see, there is already code duplicated (as in yours). So this should just be a temporary solution as you will end up with more and more duplicated lines for each directory you would like to test for. If you consider to change the design, please take the PSR-0 shema into account, it helps to streamline one's codebase and makes it easy to re-use other existing compontents in the PHP world.


function autoload_class_multiple_directory($class_name) 
{

    # List all the class directories in the array.
    $array_paths = array(
        'classes_1/', 
        'classes_2/'
    );

    foreach($array_paths as $path)
    {
        $file = sprintf('%s%s/class_%s.php', AP_SITE, $path, $class_name);
        if(is_file($file)) 
        {
            include_once $file;
        } 

    }
}

spl_autoload_register('autoload_class_multiple_directory');
飞烟轻若梦 2024-12-16 10:42:50

遵循 PSR-0

正确的做法是采用 PSR-0 命名约定,然后使用 PSR-0 兼容的自动加载器,例如 Symfony2 的 UniversalClassLoader href="https://github.com/symfony/ClassLoader" rel="nofollow">ClassLoader 组件。

例如:

a/src/ProjectA/Database/Pdo.php

<?php

namespace ProjectA\Database;

class Pdo
{
    // your code
}

b/src/ProjectB/Mail/Smtp.php

<?php

namespace ProjectB\Mail;

class Smtp
{
    // your code
}

symfony ClassLoader位于供应商中/symfony/src/Symfony/Component/ClassLoader

autoload.php

<?php

require __DIR__.'/vendor/symfony/src/Symfony/Component/ClassLoader';

use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace('ProjectA', __DIR__.'/a/src');
$loader->registerNamespace('ProjectB', __DIR__.'/b/src');
$loader->register();

本质上,它的作用是使用 spl_register_autoload 注册一个自动加载器,该自动加载器尝试将请求的类与所有注册的路径进行匹配,如果匹配,则为必需的。否则自动加载器将继续搜索。

因此,您的引导代码所做的就是包含 autoload.php,之后所有其他类都将自动加载。

Follow PSR-0

The correct way to do this is to adopt the PSR-0 naming convention, and then to use a PSR-0 compatible autoloader, such as the UniversalClassLoader from Symfony2's ClassLoader component.

For example:

a/src/ProjectA/Database/Pdo.php:

<?php

namespace ProjectA\Database;

class Pdo
{
    // your code
}

b/src/ProjectB/Mail/Smtp.php:

<?php

namespace ProjectB\Mail;

class Smtp
{
    // your code
}

The symfony ClassLoader is in vendor/symfony/src/Symfony/Component/ClassLoader.

autoload.php:

<?php

require __DIR__.'/vendor/symfony/src/Symfony/Component/ClassLoader';

use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace('ProjectA', __DIR__.'/a/src');
$loader->registerNamespace('ProjectB', __DIR__.'/b/src');
$loader->register();

What this does, in essence, is use spl_register_autoload to register an autoloader which tries to match the requested classes against all registered paths, if one matches, it is required. Otherwise the autoloader will continue searching.

So what your bootstrap code does is include autoload.php, after that all other classes will be autoloaded.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文