Использование механизма Рефлексии для решения задач навигации

leadaxe

Новичок
Использование механизма Рефлексии для решения задач навигации

Я не могу написать полную статью из-за нехватки времени, но предоставлю простой для понимания идее пример кода.
Этот код можно использовать даже на начальном уровне знаний
Коротко задача:
Хочется максимально "заточить" объект под вывод информации. Часто даже в коде опытных программистов я вижу вереницы case, обрабатывающие URL запрос. Как научить объект понимать этот запрос самостоятельно? или понятнее: Для добавления новой функциональной страницы я хочу только написать метод и поставить на него ссылку типа smartclass.php?do=show

PHP:
<?php

/**
 * PHP version 5
 * @package demo application
 * @author Shulman Alexanderl
 * @copyright BR technologies 2007
*/
	
	/**
	 * Служит оболочкой для работы с пользователем системы.
	 */
	abstract class Shell{
		/**
		 * @param int $type
		 * @return Shell
		 */
		public final static function factory($type){
			$shell=null;
			switch($type){
				case 1 : $shell=new AdminShell();
						 break;
				default: $shell=new GuestShell();
			}
			return $shell;
		}
		protected function __construct(){
			
		}
		/**
		 * out 404 error;
		 */
		public function error404(){
			echo '404 Этой страницы не существует.';
		}
		abstract public function startPage();
		public final function buildPage($action){
			if (method_exists($this, strtolower($action))){
				$method = new ReflectionMethod($this, $action);
				if ($method->isPublic()){
					$this->$action();
				}else $this->error404();
			}else{
				if (empty($action))
					$this->startPage();
				else $this->error404();
			}
		}
	}
	
?>
Далее в программе мы пишем:
PHP:
	$shell=Shell::factory(getAuthType());
	$shell->buildPage(isSet($_GET['do']) ? $_GET['do']:'');
Где getAuthType возвращает тип авторизации пользователя
а классы AdminShell и GuestShell порождены от shell и реализуют те самые "методы - функциональные страницы"

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

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

AmdY

Пью пиво
Команда форума
Полезно для новичков, тех кто ещё не научился, но не для тех кто не хочет пользоваться чужим кодом :(
Только чутка изменить
PHP:
$shell->buildPage( getAction() );
function getAction() {
// функция которая ищет переменную 'do' в $_POST или $_GET (в такой же очеродности), 
//а можно и для CLI прикрутить
// затем обрабатываем переменную
// затем возвращает результат
}
это позволяет брать экшин не только из строки запроса, но и из поста.
<form action="" method="post">
<input type="hidden" name="do" value="newAction"/>
or
<input type="submit" name="do" value="newAction"/>
</form>
 

AmdY

Пью пиво
Команда форума
одному и тому же урлу, можно обрабатывать разные экшины
/?id=fastAction - обрабатывается fastAction, а на нём форма с полем <input type="hidden" name="do" value="postAction"/>
по сабмиту попадаем на
/?id=fastAction, обрабатывает postAction
 

leadaxe

Новичок
Да это достаточно очевидное дополнение. Мы в своих системах часто используем 2-х уровневую контекстную адресацию.

Module - class,
action- method

Контекстную, т.к. Module - class для разных типов пользователей создается фабрикой разный.

Автор оригинала: dark-demon
не просёк, зачем так мудрить?
А о чем тема-то просек?


Кстати механизм рефлексии ОЧЕНЬ быстрый!
 

AmdY

Пью пиво
Команда форума
хотя лучше использовать Zend_Controller_Front, и не париться. :)
 

AmdY

Пью пиво
Команда форума
Автор оригинала: dark-demon
например, чтобы не мудрить...
это же является и ответом на твой вопрос.
когда на странице есть форма, то гораздо так проще (ИМХО), и это не "мудрить", а делает приложение более гибким.
урл - ./article.php?id=99
форма
<form action="" method="post">
<input type="text" name="article[title]" value="xxxx xxxx xxxx" />
<textarea name="article[text]">yyy yyyy yyyy yyy</textarea>

<input type="submit" name="do" value="Save" />
<input type="submit" name="do" value="Delete" />
</form>
---------------------------------------------
один урл и три событие, а иначе нужно было бы:
./article.php?id=99 - форма редактирования
./article.php?do=save&id=99 - сохранить изменения
./article.php?do=delete&id=99 - удалить статью
 

dark-demon

d(^-^)b
ну и какой смысл передавать значения полей, если нам надо удалить объект?

в моём случае урлы такие:
/article/99/ - вывод данных (view)
/article/99/edit/ - вывод формы редактирования (view)
/article/99/xml/ - вывод в виде XML (view)
... - другие view
/article/99/del/ - удаление (controller)
/article/99/mod/ - редактирование (controller)
... - длугие контроллеры

в скрипте это разруливается одним элементарным кейсом.

при этом я могу, например, удалить какую-нибудь запись просто щёлкнув на ссылку в присланном мне письме.
 

jonjonson

Охренеть
PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has been defined as abstract. Any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method's signature they cannot define the implementation.
А вызов статичных методов абстрактных классов это нормально? Ну я о первом посте в этой теме...
И ещё, код да... Ладно. О другом. Здесь смесь из авторизации, спрятанной аутентификации, выбора контроллера, модели, представления, проверки пользовательской роли и т.д. Всё в куче. В узелке. Причём примитивном (я понимаю, что в большинстве случаев достаточно для посетителя ролей гостя и админа). Не понять какая задача решалась... Разрубить узел? Не разрублен. Многое что тут отсутствует потребует повторного решения всей данной проблемы.
 

AmdY

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

в скрипте это разруливается одним элементарным кейсом.
Вот я и показываю, как избавиться от этого.

при этом я могу, например, удалить какую-нибудь запись просто щёлкнув на ссылку в присланном мне письме.
В моём варианте такое тоже возможно, параметры можно брать откуда угодно, хоть из командной строки, если они там есть.
 

leadaxe

Новичок
Автор оригинала: jonjonson
А вызов статичных методов абстрактных классов это нормально? Ну я о первом посте в этой теме...
И ещё, код да... Ладно. О другом. Здесь смесь из авторизации, спрятанной аутентификации, выбора контроллера, модели, представления, проверки пользовательской роли и т.д. Всё в куче. В узелке. Причём примитивном (я понимаю, что в большинстве случаев достаточно для посетителя ролей гостя и админа). Не понять какая задача решалась... Разрубить узел? Не разрублен. Многое что тут отсутствует потребует повторного решения всей данной проблемы.
Нормально. Давайте не много теории.
абстрагирование класса не распространяется на все его методы.
метод же статический и final, т.е. не может быть абстрагирован и как следствие переопределен.
Возможно вы путаете абстрактный метод и класс. Метод имеющий реализацию не абстрактен и может быть использован. Но экземпляр абстрактного класса не может быть создан.

Теперь по вашей теме. Здесь описан прием и его демонстрация. Естественно чтобы что-либо демонстрировать надо свести это к примитивам. Это прием, а не панацея использовать его можно успешно во многих местах, например, в разборе XML. Задача показать изящность механизма рефлексии, а то что, по вашему мнению, отсутствует сделайте сами под ваши нужды. Я сюда пришел поделиться опытом, а не дать готовые решения. Используйте Googl.

-~{}~ 07.05.07 10:58:

Автор оригинала: dark-demon
в скрипте это разруливается одним элементарным кейсом.
Последнее время есть течение, и я его сторонник, которое считает, что большие кейсы плохо наглядны и не очень гибки.
Это один из методологических приемов как писать без них. Преимущество в простоте модификации, масштабируемости и гибкости. Недостатки тоже есть. Один из них - переход от логики процедурного программирования к абстрагированию на поведение объектов.
 

AmdY

Пью пиво
Команда форума
ну, не нравится мне "в скрипте это разруливается одним элементарным кейсом"
 

leadaxe

Новичок
Автор оригинала: dark-demon
зачем? чем неявные объектные связи лучше явной алгоритмической конструкции?
Простотой модификацией, читабельностью кода, маштабированием и гибкостью. Это работает только когда проект большой и над ним работает более 1-го человека. Это надо попробовать и если понравится оценить, а так слишком много книг по техникам проектирования решений, чтоб их тут цитировать.
 

dark-demon

d(^-^)b
Последнее время есть течение, и я его сторонник, которое считает, что большие кейсы плохо наглядны и не очень гибки.
а, ну если это религиозный вопрос, то вопросов нет :)

если же нет, то чем конструкция вида:

Код:
 class myclass {
function a () {....}
function b () {....}
function c () {....}
}
нагляднее чем:

Код:
 switch ($do) {
case 'a': ...; break;
case 'b': ...; break;
case 'c': ...; break;
}
?

кроме того, можно использовать конструкции вида:
Код:
if (in_array($do,$this->allowedFunctions)) $this->$do()
выполняющие то же самое, что и в первом посте, но без плясок с бубном.
 

OZ

Новичок
PHP:
<?php
$action=$_GET['action'];

$actions['forum']='forum.inc';
$actions['gb']='gb.inc';
$actions['some']='some.inc';

if (array_key_exists($action,$actions)) include $actions[$action];
?>
Тоже самое ведь. Причём каждый модуль получит в своё распоряжение $_GET и дальше сам уже справится с дополнительными параметрами. Зачем такие сложности?
 

leadaxe

Новичок
Везде модуль тоже получает GET себе. По большей части я пишу здесь все для случая, когда проект должен быть маштабируем. Да, все решения, которые, тут приведены, очень хорошие, но подходят для задач, где вы работаете одни или для малых задач в малых коллективах и не подходят для долгосрочных проектов.
Это утверждение сделано достаточно субъективно и не претендует на полную правоту, но приведу несколько рассуждений:

Вы за кейсом пишете что код? если так, то ваш проект следует выкинуть, ибо его изменения дороже чем писать новый.
Если вы пишете не код, а вызов функции, то вам должно быть проще сгруппировать их - инкапсулировать в класс и ограничить права видимости.

Ограничивая права видимости вы повышаете стабильность вашего приложения.

Вы закончили проект вы его сделали и сдали, просто ли вам найти этот кейс для внесения изменений? Насколько это сложнее чем посмотреть сигнатуру класса в инспекторе классов?

Новый сотрудник подключился к проекту и должен дополнить функционал, что проще: сказать ему найдешь "тот-то" кейс (где искать? хорошо если он выделен в функцию) и будешь работать от него или формализовать новый функционал организовывается в классах, порожденных от "такого-то" в виде публичных методов.

При использовании процедурного подхода:
При легком добавлении функционала вы должны лезть в механизм внутренней адресации внутри системы (менять код кейса)
При использовании объектного подхода:
вы только лишь работаете с наследниками - конечными реализациями и не должны иметь доступ для изменения основной системы, она сама может быть отлажена откомпилирована и закрыта.

Вцелом используйте тот подход, который вам больше нравится. Это действительно вопрос религии.
 
Сверху