namespace и проверка на существование класса

malina95

Дракула кода:)
Здравствуйте, мне очень нужна ваша помощь, я делаю движок сайта визитки с регистрацией на ооп и mvc, у меня всё в пространстве имён, есть также автозагрузчик классов, но проблема вот в чём:

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

Если кому надо то вот мой роутер:
PHP:
<?php
	
	class Router {
		
		private $defaultController = 'IndexController';
		private $defaultAction = 'indexAction';
		
		private function getURI () {
			
			return $_SERVER['REQUEST_URI'];
			
		}
		
		public function run () {
			
			$uri = $this->getURI();
			
			//user/get/id/1 - так выгледит строка запроса
			$splits = explode('/', trim($uri, '/'));
			//Выбор контроллера
			$controller = !empty($splits[0]) ? ucfirst($splits[0]).'Controller' : $this->defaultController;
			//Выбор экшена
			$action = !empty($splits[1]) ? $splits[1].'Action' : $this->defaultAction;
			//выбор параметров
			if (!empty($splits[2])) {
				$keys = $values = array();
				for ($i = 2, $cnt = count($splits); $i < $cnt; $i++) {
					if ($i % 2 == 0)
						$keys[] = $splits[$i];
					else
						$values[]= $splits[$i];
				}
				if ($keys and $values)
					$params = array_combine($keys, $values);
			}
			
			$namec = "App\Controllers\\".$controller;
			if (class_exists($names)) {
				$controller = new $namec();
				$controller = $controller->$action($params);
				return $controller;
			}
			else error404();

		}
		
	}
	
?>
 

malina95

Дракула кода:)
PHP:
$namec = "App\Controllers\\".$controller;
            if (class_exists($names)) {
                $controller = new $namec();
                $controller = $controller->$action($params);
                return $controller;
            }
            else error404();
В этом месте нужно проверить мне кажется, если есть такой котроллер то вызвать метод, если нет то 404
 

malina95

Дракула кода:)
Фильтрации всмысле проверку адресса регулярным выражением?

Кстати если я вызову эту функцию "return print_r(get_declared_classes())" то контроллера там нет, там только автозагрузчик и этот роутер, если у вас есть готовые роутер похожий на мой, то будьте добры, дайте пожалуйста...
 

malina95

Дракула кода:)
Помогите пожалуйста, 2 день пытаюсь что-либо придумать
 

flr

Новичок
Фильтрации всмысле проверку адресса регулярным выражением?
PHP:
$namec = "App\Controllers\\".$controller;
Тут фактически $controller берётся из входящего запроса. Аналогично $action.
То есть лучше иметь подготовленный проверенный список, с которым можно сравнить входящий параметр. Если такого в списке нет, то выдавать 404. Список допустимых значений лучше, чем просто проверка регулярками или условиями, так как меньше шансы ошибиться и намного очевиднее для понимания в будущем.

если у вас есть готовые роутер похожий на мой, то будьте добры, дайте пожалуйста...
Попробуйте воспользоваться этим: https://github.com/chriso/klein.php , он хоть и не похож на ваш, но возможно вам понравится.
 

malina95

Дракула кода:)
У меня есть роутер(вы его видите выше), у меня есть автозагрузчик:
PHP:
<?php
    
	class Autoloader {
        
		private static $_lastLoadedFilename;
     
        public static function loadPackages($className) {
            $pathParts = explode('_', $className);
            self::$_lastLoadedFilename = implode(DIRECTORY_SEPARATOR, $pathParts) . '.php';
			require_once (self::$_lastLoadedFilename);
        }
       
    }
	
?>
но функция class_exists не может найти класс, меня всё время выкидывает на 404
 

flr

Новичок
PHP:
if (class_exists($names)) {
                $controller = new $namec();
}
В данном коде ты сначала проверяешь загружен ли класс, а потом только загружаешь его автолоадером. То есть твоя проверка class_exists просто не нужна.
 

malina95

Дракула кода:)
PHP:
$namec = "App\Controllers\\".$controller;
			$controller = new $namec();
			if (class_exists($controller)) {
				$controller = $controller->$action($params);
				return $controller;
			}
			else error404();
Если делать так, то всё работает, но вылазиет ошибка "Warning: require_once(App\Controllers\NotfoundgController.php) [function.require-once]: failed to open stream: No such file or directory in C:\Server\OpenServer\domains\project\Autoload.php on line 10

Fatal error: require_once() [function.require]: Failed opening required 'App\Controllers\NotfoundgController.php' (include_path='.;C:/Server/OpenServer/modules/php/PHP-5.3.23/;C:/Server/OpenServer/modules/php/PHP-5.3.23/PEAR') in C:\Server\OpenServer\domains\project\Autoload.php on line 10" как её можно скрыть от юзера?
 

flr

Новичок
Во-первых, class_exists надо применять на название класса, то есть $namec, а не на $controller.
Во-вторых, require_once в отличии от include_once кидает Fatal error, то есть дальше строчки $controller = new $namec(); твой код всё равно не пойдёт и тогда нет смысла использовать class_exists или какие-либо подобные проверки. Прикидываешься дубом и юзаешь контроллер, понимая, что если его нет, вывалится fatal.
В-третьих, скрыть любые ошибки от юзера можно с помощью ini_set('display_startup_errors', false);ini_set('display_errors', false); или прописать аналогичное в php.ini
В-четвертых, если не хочешь падать с фаталом, а хочешь отдавать 404, то тебе надо например использовать include_once в автолоадере, а дальше у тебя будет вываливаться только Warning, который ты можешь скрыть параметрами из предыдущего пункта.
В-пятых, само собой у тебя не самый удачный подход, но так как это сайт визитка, то пофиг.
 

hell0w0rd

Продвинутый новичок
PHP:
$basePath = __DIR__;
spl_autoload_register(function($className) use($basePath){
    $path = $basePath . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';

    if(!is_readable($path)) {
        throw new Exception(sprintf('Class autoloader try to load class %s from file %s, but file not readable!', $className, $path));
    }

    require $path;

    if(!class_exists($className)) {
        throw new Exception(sprintf('Class autoloader expected found class %s at file %s!', $className, $path));
    }
});
Вот наколеночная реализвация в вроде как все работает :)
А вообще лучше всего юзать composer, даже если нет никаких зависимостей и работа на пару дней.
Там приятный файл конфигурации, там есть возможность создать оптимизированный загрузчик, который будет знать о всех возможных классах и тупо их загружать когда нужно.

И еще, если у тебя не удается загрузить класс - это 500 ошибка, и никак не 404
 

malina95

Дракула кода:)
А как можно проверить количество параметров метода? Тоесть если в адрессной строке "http://project/index/show/id/5" , а у метода show нет параметров то выкинуть ошибку?
 

flr

Новичок
malina95
в твоём случае $splits хранит массив параметров. Первые два — это контроллер и экшн. Соответственно, если у тебя для экшена show значение count($splits) больше двух, то надо выдавать ошибку.
 

flr

Новичок
Эм, или ты имел в виду проинспектировать метод (то есть заранее не известно количество параметров) и проверить совпадает ли оно с количеством пришедшим от пользователя?
 

malina95

Дракула кода:)
да, имел именно это ввиду, хотя я бы мог и не париться с автоматическим роутером и поставить ручной, с регулярками типа users/:username но я не знаю как его сделать
 

hell0w0rd

Продвинутый новичок
Посмотри на нормальные реализации роутеров. Прежде чем велосипедить - полезно посмотреть что есть уже готовенькое. Ссылки дать или сам найдешь?
 
Сверху