Лучший способ загрузить класс модели в определенную папку HMVC - PullRequest
1 голос
/ 06 августа 2011

В настоящее время я пишу свой собственный 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(), что, по мнению многих, плохо, так как оно вводит зависимости.Я также могу получить applicationName, используя debug_backtrace(), поскольку класс, который инициирует модель, содержит 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);
    }
}

Ответы [ 2 ]

2 голосов
/ 07 августа 2011

Разве вы не можете просто установить статический член класса автозагрузки при запуске, содержащий всю необходимую информацию?

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 ().

0 голосов
/ 07 августа 2011

Я бы посоветовал установить определение APPLICATION_ROOT в любом файле, загружающем приложение. Это было бы полезно иметь в наличии постоянно, а не только в __autoload.

...