@kirill-93

Как проверить существование класса?

Здравствуйте.
Я делаю для лабораторной работы MVC фреймворк.

Выглядит он так:
#..
--app
----controllers
------FrontController.php
------HomeController.php
----models
----views
--public
----index.php


В index.php добавляю пути до контроллеров через
set_include_path
, описываю функцию
__autoload
и вызываю метод из FrontController.
function __autoload($class)
{
    require_once $class . '.php';
}

$app = FrontController::instance();
echo $app->run();

Тут начинаются проблемы, потому что я использую неймспейсы. Первая проблема -
__autoload
не работает и приходится его описывать так:
function __autoload($class)
{
    $parts = explode('\\', $class);

    require_once end($parts) . '.php';
}

Вторая проблема - в FrontController у меня есть метод run, который получает из REQUEST_URI имя контроллера и имя метода. Получив эти имена, я должен проверить, существет ли такой класс и метод.
Проверяю я так:
public function run()
    {
        if (class_exists($this->controller)) {
            $reflection = new \ReflectionClass($this->controller);
            //...
         }
    }


И class_exists и ReflectionClass не находят контроллер по названию, нужно добавить неймспейс.
public function run()
    {
        if (class_exists(__NAMESPACE__ . '\\' . $this->controller)) {
            $reflection = new \ReflectionClass(__NAMESPACE__ . '\\' .  $this->controller);
             //...            
        } 
    }


Как мне сделать проверку контроллера без неймспейса? Или все правильно и так и должно быть?
  • Вопрос задан
  • 1862 просмотра
Решения вопроса 1
@MadridianFox
Web-программист, многостаночник
1) это где такие лабораторные дают, что необходимо фреймворк написать?))
2) а вы уверены, что вам нужна рефлексия и динамика вообще? Почему вы считаете, что использование неймспейсов это проблема?

По PSR-4 неймспейсы как раз используются для автозагрузки классов, потому что неймспейс по сути должен повторять путь до класса. У вас какой-то не универсальный автолоад, как же файлы в других папках? Как вы будете подгружать классы из папок внутри папки controllers?
Правильный подход - получать полное имя класса (с неймспейсом) и при автолоаде просто заменять слэши на прямые, чтобы получить путь до файла.

Свой автолоад это обязательное условие? можно просто воспользоваться композером. Обязательно автолоад делать через устаревший __autoload(), а не через общепринятый spl_autoload_register()?

Создать объект класса используя его название в строке можно просто используя переменную:
$classname = "app\\controllers\\MainController";
$methodname = "actionIndex";
$controller = new $classname(); // тут сработает автолоад

$controller->{$methodname}();


При этом вы можете (и должны) обеспечить безопасность, так чтобы никто не мог передать через GET и имя класса и имя метода, и вызвать любой метод. Делается это очень легко.
Во-первых путь из GET к нам приходит имя класса без неймспейса, ну логично. Неймспейс мы потом прицепим к нему. Так никто не сможет случайно создать объект любого класса, а только объект класса из папки с контроллером. Это не возбраняется.
Во-вторых, если кто-то передал абра-кадабру, то надо не падать с ошибкой Class not found, логично. Для этого, перед созданием класса просто смотрим на то какие файлы есть в папке с контроллерами. Если там нет файла с тами же именем что и класс - то показываем 404.

Потом, перед тем как вызвать метод, проверяем что он существует функцией method_exists($obj, $method_name), опять же - метода нет -- идите-ка вы на 404.

И это нормально, что рефлексия и проверка существования класса требуют полное имя класса. Это ваш подход неверный - с самого начала вы должны прицепить к имени класса неймспейсом и работать только с полным именем.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@BorisKorobkov Куратор тега PHP
Web developer
$parts = explode('\\', $class);

Можно (new ReflectionClass($class))->getShortName(), но и так тоже сойдет.

Или все правильно и так и должно быть?

Да
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы