为什么 Codeigniter 在验证路由时不接受自动加载控制器 类?
Why Codeignitor does not accept autoload Controller classes when validating routes?
为什么 Codeignitor 在验证路由时不接受 composer autoload 中的 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 中引入的,提交消息为:
Disable autoloader call from class_exists() occurences to improve performance
Note: The Driver libary tests seem to depend on that, so one occurence in CI_Loader is left until we resolve that.
所以名义上的原因是性能。
如果你想确保控制器 classes 将在每个请求上加载,你可以将文件显式添加到 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
的调用是一个相当简单的完整性检查,以确保该文件确实定义了 class。因此,基于关于如何将控制器添加到 CodeIgniter 应用程序的假设(即所有在 application/controllers
目录中并与它们定义的 class 命名相同),在执行时绕过自动加载器是合理的那支票。
如果您想确保在需要时加载控制器,即 CodeIgniter 方式,应将它们添加到上面列出的应用程序中。
为什么 Codeignitor 在验证路由时不接受 composer autoload 中的 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 中引入的,提交消息为:
Disable autoloader call from class_exists() occurences to improve performance
Note: The Driver libary tests seem to depend on that, so one occurence in CI_Loader is left until we resolve that.
所以名义上的原因是性能。
如果你想确保控制器 classes 将在每个请求上加载,你可以将文件显式添加到 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
的调用是一个相当简单的完整性检查,以确保该文件确实定义了 class。因此,基于关于如何将控制器添加到 CodeIgniter 应用程序的假设(即所有在 application/controllers
目录中并与它们定义的 class 命名相同),在执行时绕过自动加载器是合理的那支票。
如果您想确保在需要时加载控制器,即 CodeIgniter 方式,应将它们添加到上面列出的应用程序中。