Как стать автором
Обновить

Контроллеры, основанные на механизмах рефлексии.

Время на прочтение3 мин
Количество просмотров2K
контроллер — это специализированная сущность для управления другими сущностями.
Часто используют функциональные контроллеры, основанные на найменге (naming) примеры всем широко известны, например плагины смарти:
smarty_type_name() как видите из документации, плагин становится доступным если объявлены соответствующие функции.

в целом там простой контроллер который ищет функцию по простым правилам, основанных на именовании.
часто такие вызываемые сущности хочется проинкапсулировать или иначе собрать и закрыть во что-либо, в результате появляются файлы с типично функциональным подходом:
mylib.php:
function mylib_afunc(){};
function mylib_bfunc(){};
function mylib_cfunc(){};


конечно, это не гарантирует целостности, засоряет глобальное пространство имен и проч.
Удобно такие вещи проинкапсулировать в класс:

class MyLib{
    static function a(){};
    static function b(){};
    static function c(){};
}


далее не сложно понять как нужно сделать контролер, основанный на method_exists, которому первым аргументом вполне можно давать имя класса-контейнера. Как правило, на этом фантазия останавливается, но из объектной парадигмы можно извлечь еще много различных выгод:
  • Используя наследование можно иметь «расширения» наборов таких вызываемых сущностей
  • Используя полиморфизм + наследование можно переопределять необходимые функции для тех или иных сущностей
  • Ограничение видимости поможет скрыть внутреннюю реализацию, которая должна быть скрыта от контроллера.

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

для начала покажу самый дурной вариант того как это делают:
swich $_GET['action']{
    case: "a" ...
    case: "b" ...
    case: "c" ...
}

хуже только варианты с if-elseif-else, чтоб такого не было пишут контроллер, например, как в смарти, основанный на найменге:

if (function_exists('myAction_'.$_GET['action']))
    call_user_func('myAction_'.$_GET['action']);


но я опишу немножко другой подход, более формальный:
тут код в цвете: dumpz.org/2513

а тут просто код, чтоб не бегать:


abstract class Module {
   public final function buildPage($action) {
   	do{
   		//нельзя вызвать функции, начинающиеся с подчеркивания
   		//(общепринятое соглашение считать их приватными)
		if (substr($action, 0, 1) == '_' or empty($action)) 
			break;
		//нельзя вызвать функции описанные в абстрактном классе, они для работы системы
		if (method_exists(__CLASS__, $action))
			break;
		if (!method_exists($this, $action))
			break;
		$method = new ReflectionMethod($this, $action);
		//доступны только публичные методы
		if (!$method->isPublic())
			break;
		return $this->$action();
   	}while(false);	
	return $this->error404();
   }
   public function error404(){
   		echo 'такой страницы нет в системе';
   }
}

class ExampleModule extends Module{
	function hello(){
		echo 'hello World!';
	}
	
	function test(){
		echo 'Тест!!!';
	}
	protected function inner(){
		echo 'это внутренняя функция не доступна контроллеру!';
	}
}

$module=new ExampleModule();
$module->buildPage(isset($_GET['action'])?$_GET['action']:'');


контроллером является функция "buildPage"

таким образом если вызвать скрипт
example.com/?action=hello
то попадете на работу функции hello,
а вот так вас не контроллер не пропустит:
example.com/?action=inner

примеров использования таких контроллеров масса — все ограничено лишь вашей фантазией, они успешно заменяют swich и каскады if-else, обеспечивают понятный слой абстракции, достаточно быстры и легко расширяемы.

дальнейшее развитие идеи таких контроллеров лежит в использовании наследования, например если вы узнали что ваш пользователь зарегистрирован, то ничего вам не мешает создать класс для зарегистрированных
class UserExampleModule extends ExampleModule {
     function hello(){
         echo 'привет зарегистрированный пользователь!';
     }
}

и при создании объекта писать:
if (проверка авторизации)
    $module=new UserExampleModule();
else
    $module=new ExampleModule();

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

в целом это все о чем я хотел рассказать ^_^, дальше расскажу уж просто про идею этого метода.
в первые я «изобрел» это колесо еще 2 года назад (для себя, хотя мир знал это давненько), тогда же оказалось, что такой подход используется некоторыми западными авторами-программистами, до сих пор я вижу тонны кода, в которых не используются даже простые контроллеры на найминге, вместо этого почему-то программистов прельщает писать ОГРОМНЫЕ swich, призываю вас так не поступать -), надеюсь вам этот топик поможет.

всем спасибо, не судите строго!
Теги:
Хабы:
+8
Комментарии24

Публикации

Изменить настройки темы

Истории

Работа

PHP программист
155 вакансий

Ближайшие события