在特定文件夹 HMVC 中自动加载模型类的最佳方法

发布于 2024-11-28 09:42:01 字数 2202 浏览 3 评论 0原文

我目前正在使用 HMVC 设计模式编写自己的 PHP 框架作为学习练习。这一切都有效:),但我已经读过很多次,在 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 来修复。

编辑:我现在使用 Request::getCurrentApplicationName(),而不是 Dispatcher::getApplicationName()。现在它又可以工作了,因为我的请求类保存了所有应用程序。这是更好的方法,还是有更好的方法?

<?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);
    }
}

I'm currently writing my own PHP framework as a learning exercise using the HMVC design pattern. It all works :), but I've read many times that it's a bad habit to refer to static classes in your PHP code, which is exactly what I'm doing in my autoload function:

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 . '".');
    }
}

As you can see I get the current application using the static call Dispatcher::getApplicationName(), which is bad according to many people since it introduces dependencies. I can also get the applicationName using debug_backtrace(), since the class that initiates the model contains the ApplicationName as a property. Is that better, or are there other alternatives I haven't thought of?

Thanks!

Edit: forgot to mention that there's another problem with the above code: the controller's application does not always equal the dispatcher's application, since I'm using the HMVC design pattern (so controllers are called inside controllers). This can only be fixed using debug_backtrace.

Edit: Instead of Dispatcher::getApplicationName() I now use Request::getCurrentApplicationName(). It now works again, because my request class saves all applications. Is this better, or is there a better way?

<?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);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妄想挽回 2024-12-05 09:42:01

难道您不能在启动期间设置包含所有必要信息的自动加载类的静态成员吗​​?

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'));

仅此而已。您将能够动态设置路径和应用程序名称 - 只需使用设置器更改对象的变量即可。

为什么我们应该这样做?这段代码中没有任何“魔法”。您可以使用 PHPDOC 为每个函数编写文档,并且用户将知道所有参数来自哪里。另一个优点是我可以在任何地方使用此代码,我不需要知道该类使用 Dispatcher::getApplicationName()。

Can't you just set static member of autoload class during startup containing all necessary information?

debug_backtrace() cannot be reliable source of information. What if somebody would like to use your libraries and your autoloader, but without one of the starting layers? Would it be possible that way?

All data used by class/function should be placed within that class or as parameter for the function. Because autoloader can be any callback, you can do something like this:

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'));

That's all. You will be able to set path and appname dynamically - just by changing object's variables using setters.

Why we should do that this way? In this code there is no "magic" going around. You can write documentation using PHPDOC to every function and user will know where all params come from. Another advantage is that I can use this code anywhere, I don't need to know, that the class uses Dispatcher::getApplicationName().

眼趣 2024-12-05 09:42:01

我会考虑在引导应用程序的任何文件中设置 APPLICATION_ROOT 定义。这将是一个始终可用的有用的东西,而不仅仅是在 __autoload 中。

I'd consider setting an APPLICATION_ROOT definition in whatever file bootstraps the application. That would be a useful thing to have available all the time, not just in __autoload.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文