【问题标题】:spl autoload register errorspl 自动加载寄存器错误
【发布时间】:2018-12-04 07:06:27
【问题描述】:

我正在编写一些我想使用spl_autoloader_register() 函数加载的类。我创建了一个名为 autoloader.php 的文件,并将它保存在我保存项目所需的所有类的文件夹中。 因此,为了验证它是否有效,我在测试 php 页面中使用 require_once 加载了它,但不幸的是控制台日志显示错误输出 PHP Warning: include_once(lib\DataManager.php): failed to open stream: No such file or directory

测试文件位于托管所有课程的同一文件夹中,是否因为此动机而出现此错误?

这是自动加载器代码

<?php 
function autoloader($className){
    include_once($className . '.php');
}

spl_autoload_register('autoloader');

?>

这是我尝试从测试页面实例化它的方式

<?php

require_once 'autoloader.php';
require_once 'config.php';

use lib\DataManager as DataManager;

$dataManager = new DataManager($db);

?>

【问题讨论】:

    标签: php spl-autoload-register


    【解决方案1】:

    你几乎是对的。问题是因为它没有指向正确的本地文件系统来查找文件。以下自动加载器将使用相对插件模型和库文件夹模型。这将假定您在配置文件中定义了一个变量$GLOBALS['config']-&gt;lib,该变量定义了一个可能包含额外系统库的文件系统文件夹。当然,这可以不同的定义,这取决于应用程序。

    <?php 
    function autoloader($className){
        $paths=[getcwd(),$GLOBALS['config']->lib];
        foreach($paths as $p){
            $filename = str_replace('\\','/',$p.'/'.$className.'.php');
            if (is_readable($filename)) {
                require_once($filename);
                return;
            }
        }
    }
    spl_autoload_register('autoloader');
    ?>
    

    这将考虑两种情况,类是相对于最后请求的脚本,如果不是,则尝试使用类的预定义文件夹。一旦找到并加载它应该返回,以避免继续尝试加载其他路径。

    在阵列上可以定义更多的路径来尝试,但出于性能原因,尽量不要超过四个路径。此外,路径的顺序是首先查找的优先级。

    这个脚本应该可以在 PHP 5.4 上运行。

    【讨论】:

    • 我是 PHP 这个高级概念的新手,所以我很高兴能得到您的帮助。现在我正在同一个文件夹中测试自动加载功能,但据我所知,如果我想从项目的另一个文件夹中使用它,我也需要调整它以使其工作,对吗?
    • 我不确定您所说的“相对于最后请求的文件”是什么意思。 __FILE____DIR__ 常量代表文件和目录在哪里使用,不受程序中任何其他内容的影响。
    • @Carlos H 我试过了,但它会产生同样的错误。也许我在命名空间上做错了什么?
    • @user9741470 假设您的类与您请求的脚本相关,则此方法有效。这是 Web 应用程序还是 CLI 应用程序?通常,在我的项目中,我会创建一个“库”文件夹来放置我的所有类,这种模型适用于固定应用程序。但是,相对执行模型对插件模型很有用。
    • 该类适用于普通的网络应用程序。类的路径将是 u/lib/classes.php 所以现在我遇到的问题是自动加载器会在 lib 文件夹中查找并且找不到所需的类文件,但它们都在那个路径中。将来我想从前端控制器使用自动加载,所以我想解决这个问题并了解我做错了什么。
    【解决方案2】:

    相对路径不是相对于写入它们的文件进行处理,而是相对于 PHP 进程的“当前工作目录”(通常是 Web 进程的文档根目录,但不值得依赖)。

    为了引用当前源文件的位置,PHP提供了两个magic constants

    • __FILE__ 是您编写的任何源文件的完全限定文件名
    • __DIR__ 是包含该文件的目录

    因此,假设您的类与自动加载器函数的定义位于同一目录中,您可以这样写:

    function autoloader($className){
        include_once __DIR__ . DIRECTORY_SEPARATOR . $className . '.php';
    }
    

    __DIR__ 在函数编译时被解析一次,所以每当运行这个函数时,它总是会引用 这个函数被定义的目录,而不管它在哪里被调用来自,或者脚本是如何运行的。

    (请注意,includerequireinclude_oncerequire_once 是关键字而不是函数,并且不需要将它们括起来。通常添加它们不会有什么坏处,但可能会导致在某些情况下会造成混淆,因此最好避免。)

    【讨论】:

    • 我已经尝试过__DIR__,但我得到了同样的错误PHP Warning: include_once(): Failed opening '/Applications/MAMP/htdocs/kiraMVC/u/lib/lib\DataManager.php' for inclusion (include_path='.:/Applications/MAMP/bin/php/php7.0.8/lib/php') in /Applications/MAMP/htdocs/kiraMVC/u/lib/autoloader.php on line 3 [25-Jun-2018 19:20:39 Europe/Berlin] PHP Fatal error: Uncaught Error: Class 'lib\DataManager' not found in /Applications/MAMP/htdocs/kiraMVC/u/lib/demo.php:11
    • @user9741470 那么,正确的路径是什么?调试的第一条规则是总是分解问题:尝试使用string functions 帮助您写一行显示正确完整路径的echo。然后把它放在include_once旁边。
    • 正确的路径是kiraMVC/u/lib/,但是自动加载器在 te lib 文件夹中找不到文件
    • @user9741470 仔细阅读错误信息。 '/Applications/MAMP/htdocs/kiraMVC/u/lib/lib\DataManager.php' 是不是正确的文件路径?
    • @user9741470 再次分解问题。你有两个字符串:一个目录名,你可以通过写echo __DIR__; 知道,和一个类名,你可以通过写echo $className; 来检查。现在扔掉你所有的代码,写一个只包含这两个字符串的 PHP 文件,并使用字符串函数,直到它回显你知道该类已定义的路径;不要考虑加载或相对路径,只需制作该字符串即可。一旦你这样做了,你的自动加载器的逻辑就会变得很明显;如果它因其他情况而中断,请重复该练习。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 2010-12-15
    • 2013-07-19
    • 1970-01-01
    相关资源
    最近更新 更多