为什么Codeignitor在验证路由时不接受自动加载控制器类? 其他

问题描述

为什么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;
            }
        }
    }

解决方法

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

禁用class_exists()事件中的自动加载程序调用以提高性能

注意:Driver库测试似乎依赖于此,因此在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目录中且​​名称与它们定义的类相同)的假设,执行该检查时绕过自动加载器是合理的。 / p>

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...