【问题标题】:Why Codeignitor does not accept autoload Controller classes when validating routes?为什么 Codeigniter 在验证路由时不接受自动加载控制器类?
【发布时间】:2020-10-02 05:51:12
【问题描述】:

为什么 Codeignitor 在验证路由时不接受 Composer 自动加载中的 Controller?

它正在检查:class_exists($class, FALSE),其中第二个参数禁用自动加载检查。

https://github.com/bcit-ci/CodeIgniter

    $e404 = FALSE;
    $class = ucfirst($RTR->class);
    $method = $RTR->method;

    if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php'))
    {
        $e404 = TRUE;
    }
    else
    {
        require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php');

        if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
        {
            $e404 = TRUE;
        }
        elseif (method_exists($class, '_remap'))
        {
            $params = array($method, array_slice($URI->rsegments, 2));
            $method = '_remap';
        }
        elseif ( ! method_exists($class, $method))
        {
            $e404 = TRUE;
        }
        /**
         * DO NOT CHANGE THIS, NOTHING ELSE WORKS!
         *
         * - method_exists() returns true for non-public methods, which passes the previous elseif
         * - is_callable() returns false for PHP 4-style constructors, even if there's a __construct()
         * - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited
         * - People will only complain if this doesn't work, even though it is documented that it shouldn't.
         *
         * ReflectionMethod::isConstructor() is the ONLY reliable check,
         * knowing which method will be executed as a constructor.
         */
        elseif ( ! is_callable(array($class, $method)))
        {
            $reflection = new ReflectionMethod($class, $method);
            if ( ! $reflection->isPublic() OR $reflection->isConstructor())
            {
                $e404 = TRUE;
            }
        }
    }

【问题讨论】:

    标签: php codeigniter autoload


    【解决方案1】:

    查看 git 历史记录,更改是在 49e68de96b420a444c826995746a5f09470e76d9 中引入的,提交消息为:

    从 class_exists() 事件中禁用自动加载器调用以提高性能

    注意:驱动程序库测试似乎依赖于此,因此在我们解决该问题之前,CI_Loader 中会出现一次。

    所以名义上的原因是性能。

    如果你想确保控制器类会在每个请求中加载,你可以将文件显式添加到 Composer autoload.files 属性中,如下所示:

    composer.json
    {
        "autoload": {
            "files": [
                "src/Foo.php"
            ]
        },
        "name": "test/64166739"
    }
    
    src/Foo.php
    <?php
    class Foo {}
    
    test.php
    <?php
    $loader = require('./vendor/autoload.php');
    var_dump(class_exists('Foo', false));
    

    运行时(例如通过php test.php),我们得到以下输出:

    bool(true)
    

    附加

    查看围绕对class_exists 的调用的代码,看起来控制器文件应该遵循这样的约定,例如,对于内置的Welcome 控制器和默认设置,定义它的文件应该存在于:

    application/controllers/Welcome.php

    所以在require_once该文件之后,对class_exists 的调用是一个相当简单的健全性检查,以确保该文件确实定义了该类。因此,基于关于如何将控制器添加到 CodeIgniter 应用程序的假设(即所有控制器都在 application/controllers 目录中并命名为与它们定义的类相同),执行该检查时绕过自动加载器是合理的。

    如果你想确保控制器在需要时加载,CodeIgniter 方式,它们应该被添加到上面列出的应用程序中。

    【讨论】:

    • 很高兴知道它以何种方式提高性能。
    • 同意 :) 我想我们可以问github.com/narfbg
    • 尽管我已经设置了 config['composer_autoload'] = TRUE,但这种行为使它无法检测到我使用命名空间声明的控制器。当我删除检查文件并将其更改为 class_exists($class, TRUE) 时性能仍然可以吗?我的作曲家配置是:“autoload”:{“classmap”:[“vendor/codeigniter/framework/system”,“vendor/codeigniter/framework/application”,“application/domain”,“application/controllers”]},
    • @NguyễnLouis 在性能方面,您必须检查它是否启用和禁用自动加载,看看是否有任何明显的差异。关于命名空间,我相当确定 CodeIgniter 将无法加载命名空间控制器。 routes.php 甚至没有真正的语法允许它;使用类似$route['other-welcome'] = 'other/welcome/index' 的东西只是尝试加载不存在的Other 类,而不是Other\\Welcome 控制器。
    • 我正在升级 CodeIgniter3 项目以支持命名空间控制器。幸运的是,我的改变奏效了:)出于性能考虑,我会更多地跟踪它。感谢您的有用回答;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 2014-02-17
    • 2015-10-30
    • 1970-01-01
    相关资源
    最近更新 更多