2015-03-24 3 views
0

У меня есть структура MVC в моем php.PHP - Предотвращение ошибки автозагрузчика

Я использую автозагрузку для инициализации правильного контроллера.

Вот очень упрощенная вниз версия моего index.php:

<?php 
spl_autoload_extensions('.class.php'); 
spl_autoload_register(); 

$controller = strtolower($_GET["controller"]); 
$action = strtolower($_GET["action"]); 

$obj = new $controller(); 
$obj->{$action}(); 

Так скажем, пользователь загружает www.example.com/Page/View. Apache перепишет его на www.example.com?controller=Page&action=View. Затем, когда php вызывает $obj = new $controller();, он попытается найти page.class.php в том же каталоге, что и файл (очевидно, что в моем приложении структура файла не такая тривиальная, с пространствами имен и т. Д.), А затем загрузите класс Page внутри и выполнить Page->View();.

Теперь скажите, что пользователь делает опечатку и пытается загрузить www.example.com/Pagr/View. В идеале, он должен получить ответ заголовка 404. Но с текущей реализацией php просто выбросит Fatal error, когда он не сможет загрузить автозагрузку pagr.class.php.

Как предотвратить эту ошибку? Я провел некоторое исследование, и я не могу найти способ проверить, может ли класс быть загружен автоматически или нет до вызова new.

+0

Как насчет использования блока try-catch? try { $ obj = new $ controller(); } catch (ExceptionThrownOnNotClassFound) { // создать 404 ответ } – Warzyw

+1

Не удается обнаружить фатальную ошибку. – Nikita240

+0

Я просто пытаюсь угадать здесь. Возможно, проверка того, существует ли класс $ obj с классом_exists, может помочь вам – FranMercaes

ответ

4

Используйте class_exists(), чтобы проверить, существует ли класс, прежде чем пытаться его загрузить.

Однако, вот как я бы это сделать:

class ClassNotFoundException extends Exception {} 

function autoloadClass($class) { 
    $file = $class . '.class.php'; 

    if(!file_exists($file)) { 
    throw new ClassNotFoundException($class); 
    } 

    require($file); 
} 

spl_autoload_register('autoloadClass'); 

try { 
    $obj = new $controller(); 
} 
catch(ClassNotFoundException $e) { 
    // call 404 page 
} 
+0

'class_exists()' проверяет, загружен ли класс. Он не проверяет, может ли быть автозагрузка. – Nikita240

+0

Вы не можете проверить наличие файла? –

+0

@halloei. Ваша реализация является наиболее очевидной, однако люди сообщают, что, по-видимому, php игнорирует исключения, брошенные внутри функции '__autoload', и в любом случае выбрасывает« Fatal error ». См. [This] (http://stackoverflow.com/a/1589227/2449639). – Nikita240

1

Если то, что вы абсолютно необходимо не способ проверить, если класс может быть автоматически загружаются. В противном случае, если вам нужно проверить наличие файла контроллера до создания объекта, вы можете попробовать:

if(file_exists(strtolower($controller).'.class.php') && class_exists ($controller, false)) 
{ 
    $obj = new $controller(); 
} 

Второй аргумент, передаваемый class_exists() гарантирует, что он не пытается автозагрузка класса. Я не знаю, поможет ли это вам в любом случае.

+0

Ну, это должно быть немного сложнее, потому что для правильной реализации вам нужно было бы рассчитать путь include и namespacing, но да, вы можете проверить, существует ли файл. Но проблема в том, что он все равно выдает ошибку, если класс не может быть найден в файле, что является ситуацией, в которой вы все равно хотите вернуть 404. – Nikita240

+1

. Лучше всего будет совместить проверку выше с тем, что @halloei предлагает. Я уточню свой ответ, чтобы понять, что я имею в виду. – NaijaProgrammer

1

@halloei является правильным, но для этого требуется комментарий, чтобы объяснить, почему это правильно. class_exists - еще одна смешная PHP-функция, которая пытается автозагрузить класс, если он не существует. Это довольно противоречиво, но так оно и работает (это поведение можно отключить вторым аргументом). Итак, class_exists не скажет вам, существует ли класс, но если он существует или доступен для зарегистрированных автозагрузчиков.

+0

Хм. Когда я пытаюсь запустить 'class_exists' в классе, который не может быть загружен автоматически, он выдает' LogicException'. [Это, по-видимому, ошибка в php] (https://bugs.php.net/bug.php?id=52339). – Nikita240

+0

@ Nikita240 Я предполагаю, что проверка пути/исключение - это ваш единственный вариант здесь. Но я настоятельно рекомендую вам избежать этого шаблона и переписать архитектуру просто потому, что любой может вызвать '__construct()' в любом классе или даже сделать что-то еще хуже. – Etki

+0

Можете ли вы подробно остановиться на проблеме архитектуры? – Nikita240

0

Вот один из способов сделать это.

class_exists() предположительно пытается выполнить автозагрузку класса, если он еще не определен. Тем не менее, есть bug в настоящее время на php, который делает class_exists() забрасывать LogicException, если автозагрузчик терпит неудачу. Но мы можем просто поймать это исключение, пока ошибка не будет исправлена!

<?php 
spl_autoload_extensions('.class.php'); 
spl_autoload_register(); 

$controller = strtolower($_GET["controller"]); 
$action = strtolower($_GET["action"]); 

try { 
    $class_exists = class_exists($controller); 
} 
catch(LogicException $e) { 
    $class_exists = false; 
} 
finally { 
    if(!$class_exists) { 
     http_response_code(404); 
     exit(); 
    } 
} 

$obj = new $controller(); 
$obj->{$action}(); 
Смежные вопросы