【问题标题】:Autoload namespaces based on directory structure基于目录结构自动加载命名空间
【发布时间】:2015-06-01 09:08:37
【问题描述】:

根据PHP页面顶部的评论spl_autoload_register( )

对于使用命名空间类的 PHP 5.3 用户来说是个好消息:

当您创建与包含类的名称空间匹配的子文件夹结构时,您甚至不必定义自动加载器。

<?php
    spl_autoload_extensions(".php"); // comma-separated list
    spl_autoload_register();
?>

但是,当我有以下结构时:

* classes/someclass.php

* index.php

其中someclass.php 包含以下内容:

<?php
    class someclass {
        function __construct( ) {
            echo 'It works!';
        }
    }
?>

index.php 包含:

<?php
    spl_autoload_extensions(".php");
    spl_autoload_register();

    new classes\someclass;
?>

然后我得到以下错误:

致命错误:spl_autoload(): Class classes\someclass could not be 已加载

我弄错了吗?我怎样才能做到这一点?

来自 cmets

这对课程也不起作用:

<?php
    namespace classes;
    class someclass {
        function __construct( ) {
            echo 'It works!';
        }
    }
?>

【问题讨论】:

  • @OhAuth 对不起。我完全知道你怎么可能认为这是一个重复的甚至是远程相关的。
  • someclassclasses 命名空间中不是。命名空间与目录不同。
  • 前段时间我在 php.net 上写了那条评论,当时我在 Windows 系统上工作。后来,我不得不在another comment 的同一页面上部分撤销我在该评论中写的内容,其中还包含我能想到的最简单的问题的可能解决方案(除了使用 Composer)。
  • @BhargavRao 为什么 SednaSoft 的回答被删除了?

标签: php autoload autoloader spl-autoload-register


【解决方案1】:

在您的 someclass.php 文件中,您必须在开始时定义命名空间。

<?php 
namespace classes;

【讨论】:

    【解决方案2】:

    TLDR;它有效,但是:

    • classes/someclass.php 中缺少 namespace classes;
    • set_include_path(__DIR__);index.php 中丢失
    • spl_autoload_extensions(".php") 不是必须的)

    包含路径

    SPL autoload implementation 是基于路径的。使用点作为包含路径是相对于独立于脚本文件位置的工作目录 (!)。如果classes 文件夹与场景中的index.php 文件相邻,__DIR__ 会命名所需的确切目录。

    目录分隔符映射

    接下来,自动加载器实现会在 Unix 系统上正确映射类命名空间分隔符。万一在o / p中丢失了,the PHP source code clearly has this

    文件名区分大小写

    源代码还显示file-names to load are made lowercase。也就是说,如果您的文件系统区分大小写,则文件名和目录名必须小写。


    参考文献:


    【讨论】:

    • 前两个参考是针对 PHP 7 的。
    【解决方案3】:

    用户SedaSoft,发布了你所指的Good news comment,后来由于想法的修改,发布了another comment

    我之前在这里所说的仅适用于 Windows。内置的 调用时注册的默认自动加载器 spl_autoload_register() 没有任何参数,只需添加 合格的类名加上注册的文件扩展名 (.php) 到每个 的包含路径并尝试包含该文件。

    示例(在 Windows 上):

    包括路径:

    - "."
    - "d:/projects/phplib"
    

    要加载的限定类名:

    network\http\rest\Resource
    

    会发生什么:

    PHP 尝试加载

    '.\\network\\http\\rest\\Resource.php'
    -> file not found
    

    PHP 尝试加载

    'd:/projects/phplib\\network\\http\\rest\\Resource.php'
    -> file found and included
    

    注意文件路径中的斜杠和反斜杠。在 Windows 上这个 完美运行,但在 Linux 机器上,反斜杠不起作用 此外,文件名区分大小写。

    这就是为什么在 Linux 上快速简便的方法是将这些转换为 限定的类名改为斜杠和小写,并将它们传递给 像这样的内置自动加载器:

    <?php
    spl_autoload_register(
      function ($pClassName) {
        spl_autoload(strtolower(str_replace("\\", "/", $pClassName)));
      }
    );
    ?>
    

    但这意味着,您必须使用小写文件保存所有类 名字。否则,如果省略 strtolower 调用,则必须使用 类名与文件名指定的完全一致,可以是 对于用非直截了当定义的类名很烦人 像e这样的情况。 G。 XMLHttpRequest.

    我更喜欢小写的方法,因为它更容易使用并且 文件名转换可以在部署时自动完成。


    请注意,此评论者今天实际上已在 SO 上发布了答案,其中包含上述链接(以及简短的解释),但随后被删除,而在 review queue 中 - 大概是因为它的简洁性。我已恢复评论者的答案以及链接的内容。他们的回答如下:

    前段时间我在 php.net 上写了那条评论,当时我正在做一个 视窗系统。后来,我不得不部分撤销我在那写的 在另一条评论中评论同一页面,其中还包含 我能想到的最简单的问题的可能解决方案 (除了使用 Composer)。

    这是原答案的截图:

    【讨论】:

      【解决方案4】:

      不要滚动你自己的自动加载,而是使用composer

      在项目的根目录中创建composer.json

      {
          "autoload": {
              "psr-4": {
                  "classes\\": "classes/"
              }
          }
      }
      

      安装composer,然后运行

       composer dump-autoload 
      

      在您的index.php 中,需要自动加载器:

      require __DIR__ . '/vendor/autoload.php';
      

      参考见

      【讨论】:

      • 我自己滚就好了,只是说...例如github.com/ArtisticPhoenix/Evo/blob/master/EVO/Autoloader.php
      • @ArtisticPhoenix 但是为什么呢?
      • 为什么?因为我不希望我的代码依赖于任何第三方系统。这是一个原因,另一个原因是我的 AutoLoader 可以注册多个命名空间路径对,这样我就可以重新建立我的命名空间(将它们重置到顶级文件夹),因为我可以。
      • @ArtisticPhoenix 如果您仔细查看github.com/ArtisticPhoenix/Evo,它已经依赖于至少七个第三方系统。看看wiki.c2.com/?WheelFactorywiki.c2.com/?NotInventedHere。虽然自己构建这些系统肯定很有趣,也是一种练习,但您的努力将更明智地花在其他事情上。
      • 什么第三方系统? php?哈哈,我的意思是框架(如代码库),无论如何,我是一名全职 PHP 高级开发人员和 CIO,所以我通常会花时间维护 4 个网站和一个在 Rabbit、Sphinx 和 Mongo 上运行的自定义 B2B 平台。所以......是的......虽然这可能会让人难过,但编码是我的乐趣,毕竟我已经结婚了,还有十几岁的孩子。
      【解决方案5】:

      如果要加载的文件只有 php 扩展名,请不要使用 spl_autoload_extensions () 函数。 就我而言,我创建了一个名为 autoload .. 的类,类似于:

      <?php
      
      class Autoload
      {
          private static $_extensions = array(
              0 => '.inc',
              1 => '.lib.php',
              2 => '.class.php',
          );
      
          public function __construct()
          {
              self::set_include_path();
              spl_autoload_extensions(implode(',', self::$_extensions));
              spl_autoload_register(__CLASS__, 'load_class');
          }
      
          public static function set_include_paths()
          {
              set_include_path(implode(PATH_SEPARATOR, array(
                  realpath('classes');
                  realpath('system');
                  ...
                  get_include_path();,
              )));
          }
      
          public function load_class($class)
          {
              if (!empty($class)) {
                  spl_autoload($class);
              }
      
              return false;
          }
      }
      

      文件末尾不用?&gt;

      【讨论】:

        猜你喜欢
        • 2013-06-29
        • 2014-11-02
        • 1970-01-01
        • 2010-11-01
        • 2011-11-19
        • 2013-11-25
        • 2014-04-13
        相关资源
        最近更新 更多