我目前正在编写自己的PHP框架作为使用HMVC设计模式的学习练习。一切正常:),但我已多次读过,在PHP代码中引用静态类是一个坏习惯,这正是我在自动加载函数中所做的:
function __autoload($className) {
$path = SERVER_ROOT . DS . 'applications' . DS . Dispatcher::getApplicationName() . DS . 'models' . DS . 'class.' . strtolower($className) . '.php';
if (file_exists($path)) {
require_once($path);
} else {
throw new Exception('Can\'t find a model at "' . $path . '".');
}
}
正如您所看到的,我使用静态调用Dispatcher::getApplicationName()
获取当前应用程序,由于它引入了依赖项,因此很多人都认为这是不好的。我也可以使用debug_backtrace()
获取applicationName,因为启动模型的类包含ApplicationName作为属性。这样更好,还是有其他我没有想过的选择?
谢谢!
编辑:忘了提到上面的代码还有另外一个问题:控制器的应用程序并不总是等于调度程序的应用程序,因为我使用的是HMVC设计模式(因此控制器被称为内部控制器)。这只能使用debug_backtrace
修复。
修改:而不是Dispatcher::getApplicationName()
我现在使用Request::getCurrentApplicationName()
。它现在再次起作用,因为我的请求类保存了所有应用程序。这样更好,还是有更好的方法?
<?php
class Request {
private static $_controllers = array();
private static $_applicationsNames = array();
public static function _getCurrentApplicationName() {
return end(self::$_applicationsNames);
}
public static function _load($applicationName, $controllerName, $methodName) {
// Add the application the the array (for autoloading).
self::$_applicationsNames[] = $applicationName;
// Check if the controller has already been instantiated.
if (!isset(self::$_controllers[$applicationName . DS . $controllerName])) {
require_once(APPLICATIONS_ROOT . DS . $applicationName . DS . 'controllers' . DS . 'class.' . $controllerName . '.php');
self::$_controllers[$applicationName . DS . $controllerName] = new $controllerName($applicationName);
}
// Get the user arguments.
$arguments = array_slice(func_get_args(), 3);
// Call the method.
$result = call_user_func_array(array(self::$_controllers[$applicationName . DS . $controllerName], $methodName), $arguments);
// Remove the last value from the applications array.
array_pop(self::$_applicationsNames);
}
}
答案 0 :(得分:2)
难道你不能在启动过程中设置包含所有必要信息的autoload类的静态成员吗?
debug_backtrace()不能是可靠的信息源。如果有人想使用您的库和您的自动加载器,但没有其中一个起始层,该怎么办?这样可能吗?
类/函数使用的所有数据都应放在该类中或作为函数的参数。因为自动加载器可以是任何回调,所以你可以这样做:
class FrameworkAutoloader
{
public $appName;
public $path;
public function setAppName($name) { $this->appName = $name; }
public function setPath($path) { $this->path= $path; }
function __autoload($className) {
$path = $this->path. DS . 'applications' . DS . $this->appName . DS . 'models' . DS . 'class.' . strtolower($className) . '.php';
if (file_exists($path)) {
require_once($path);
} else {
throw new Exception('Can\'t find a model at "' . $path . '".');
}
}
}
$autoloader = new FrameworkAutoloader();
$autoloader->setAppName('asd'); //you can also apply those within constructor, but leave setters
$autoloader->setPath('asd');
spl_autoload_register(array($autoloader, '__autoload'));
这就是全部。您将能够动态设置路径和appname - 只需使用setter更改对象的变量即可。
为什么我们应该这样做?在这段代码中,没有“神奇”的存在。您可以使用PHPDOC为每个函数编写文档,用户将知道所有参数的来源。另一个优点是我可以在任何地方使用此代码,我不需要知道,该类使用Dispatcher :: getApplicationName()。
答案 1 :(得分:0)
我会考虑在任何文件引导应用程序时设置APPLICATION_ROOT
定义。这是一个有用的东西,一直可用,而不仅仅是__autoload
。