PHP: я смешиваю событийное Программирование с сигнальными интерфейсами (сигнал и слоты / шаблон наблюдателя)?
Я видел много людей, говорящих, что Symfony2, Zend Framework 2 и другие управляются событиями.
в настольном мире, с помощью событийного программирования я понимаю, что приложение будет уведомлять своих наблюдателей всякий раз, когда его состояние изменяется.
поскольку PHP-приложения не имеют состояния, нет способа сделать это. Т. е. наличие наблюдателей, привязанных к виду, наблюдающих за изменениями, пока пользователь использует интерфейс. Вместо этого ему нужен новый процесс запроса, чтобы обновить представление. Итак,это не событие, а целый новый запрос.
С другой стороны, есть аналогичная концепция: архитектура, управляемая событиями.
здесь вы можете читать как:
http://en.wikipedia.org/wiki/Event-driven_programming
http://en.wikipedia.org/wiki/Event-driven_architecture
и здесь:
http://en.wikipedia.org/wiki/Signal_programming
сигнал-это уведомление процесса о том, что произошло событие. Сигналы иногда описываются как программные прерывания. Сигналы аналогично аппаратным прерываниям в том, что они прерывают нормальное поток выполнения программы; в большинстве случаев невозможно точно предсказать, когда придет сигнал.
- тег Stackoverflow [singals] описание
более того, то, что я называл управляемым событиями, кажется более связанным с сигналами и шаблонами слотов, введенными Qt (реализация шаблона наблюдателя)
в качестве примера есть структура Prado, которая утверждает, что она управляется событиями:
http://www.pradosoft.com/demos/quickstart/?page=Fundamentals.Applications (Жизненные Циклы Приложений раздел)
http://www.pradosoft.com/docs/manual/System/TApplication.html#methodonEndRequest
IIRC, это не приложение, управляемое событиями, а просто подключаемые крючки (сигналы и слоты), используемые классами, которые реализуют observable Interface
. Я имею в виду, учитывая, как настольные приложения используют события и как приложения без состояния используют события (как plugi-ns): первые используют события для всего приложения, включая представления, последние только для операции на стороне сервера.
один больше связан с аспектно-ориентированным программированием (с сигналами и слотами), а другой специально не привязан к общие вопросы / AOP. Другими словами, это больше связано с состоянием приложения.
Итак, что же на самом деле связь между этими терминами и как они отличаются друг от друга?
- программирование на основе событий
- архитектура, управляемая событиями
- сигналы и Шаблон Слоты
эти термины просто общие шаблоны? Следовательно, все, что реализует шаблон наблюдателя, можно считать управляемым событиями?
обновление
Zend Framework 2
статья о AOP, которую я связал выше (http://mwop.net/blog/251-Aspects, - фильтры, - и-сигналы, - о, - мой!.html ) был написан Мэтью Вейером О'Финни (ZF Leader). Если не ошибаюсь, это не есть упоминания о "event-driven", просто сигнал и слоты.
Symfony 2
С Использованием Symfony2
EventDispatcher
описание компонента не содержит упоминаний о для "событийной" приложений: http://symfony.com/doc/current/components/event_dispatcher/introduction.html Он содержит только ссылки на" события " (которые, действительно, обрабатываются сигналом и слотами).
обе структуры, похоже, используют шаблон фильтра перехвата внутри сигнал и слоты для того чтобы отрегулировать одновременные события во время процесса запроса.
2 ответов
отказ от ответственности: это длинный ответ, но я думаю, что это стоит читать с все его ссылки. И ИМХО это приводит к окончательному ответу.
я боролся на эту тему последние пару дней, и, если я все правильно прочитал, ответ:
Event-driven !== Запрос-driven
"[...] Я нахожу это самое интересное различие в событии сотрудничества перефразируя Джона Уделла: запрос управляемого программного обеспечения говорит когда говорят, программное обеспечение, управляемое событиями, говорит, когда ему есть что сказать.
следствием этого является то, что ответственность за управление государством сдвиги. В сотрудничестве запроса вы стремитесь обеспечить что каждая часть данных имеет один дом, и вы смотрите его из этого дома, если хотите он. Этот дом отвечает за структуру данных, как долго это хранится, как получить к нему доступ. В сценарии сотрудничества событий этот источник новых данных приветствуется, чтобы забыть данные во второй раз передается в конечную точку сообщения."
Мартин Фаулер - сотрудничество событий (раздел запросов)
основываясь на этом утверждении, IIRC, современные фреймворки PHP реализуют шаблон Observer + перехватывающие фильтры + Singal и слоты, чтобы вызвать некоторые события во время цикла запроса.
но, несмотря на то, что он принимает некоторые идеи event-driven архитектуры, похоже, не поддерживают, что вся структура управляется событиями (т. е. Symfony2-это управляемый событиями framewrok).
мы привыкли делить программы на несколько компонентов, которые сотрудничать вместе. (Я использую неопределенное слово "компонент" здесь намеренно, так как в этом контексте я имею в виду много вещей: в том числе объекты в программе и несколько процессов, взаимодействующих между собой сеть.) Наиболее распространенным способом заставить их сотрудничать является стиль запроса / ответа. Если объект customer хочет получить некоторые данные из объект salesman, он вызывает метод на объекте salesman, чтобы задать его за эти данные.
другой стиль сотрудничества-это совместные события. В этом стиле у вас никогда нет одного компонента, который просит другого что-либо сделать, вместо каждый компонент сигнализирует о событии, когда что-то меняется. Другой компоненты слушают это событие и реагируют так, как они хотят. Этот известный шаблон Observer является примером сотрудничества событий.
Мартин Фаулер - фокус на событиях (раздел: Использование событий для сотрудничать)
Я думаю, что PHP-приложения более тесно связаны с событиями, чем с запросами только когда внимание сосредоточено на событиях. Если эти приложения / фреймворки используют события только для межсекторальных проблем (AOP), то это не зависит от событий. Точно так же вы не назвали бы это тест-драйв или управляемый доменом только потому, что у вас есть некоторые объекты домена и модульные тесты.
примеры реального мира
Я выбрал несколько примеров, чтобы показать, почему эти рамки не полностью управляются событиями. Несмотря на события AOP, все запрос-driven:
Примечание: хотя, он может быть адаптирован для управления событиями
Zend Framework 2
рассмотрим \В Zend\MVC В\Приложения компонент:
он реализует \Zend\EventManager\EventManagerAwareInterface и полагается на \Zend\Mvc\MvcEvent который описывает возможные события:
class MvcEvent extends Event
{
/**#@+
* Mvc events triggered by eventmanager
*/
const EVENT_BOOTSTRAP = 'bootstrap';
const EVENT_DISPATCH = 'dispatch';
const EVENT_DISPATCH_ERROR = 'dispatch.error';
const EVENT_FINISH = 'finish';
const EVENT_RENDER = 'render';
const EVENT_ROUTE = 'route';
// [...]
}
The \В Zend\MVC В\Приложения сам компонент управляется событиями, потому что он не взаимодействует напрямую с другими компонентами, но вместо этого он просто запускает события:
/**
* Run the application
*
* @triggers route(MvcEvent)
* Routes the request, and sets the RouteMatch object in the event.
* @triggers dispatch(MvcEvent)
* Dispatches a request, using the discovered RouteMatch and
* provided request.
* @triggers dispatch.error(MvcEvent)
* On errors (controller not found, action not supported, etc.),
* populates the event with information about the error type,
* discovered controller, and controller class (if known).
* Typically, a handler should return a populated Response object
* that can be returned immediately.
* @return ResponseInterface
*/
public function run()
{
$events = $this->getEventManager();
$event = $this->getMvcEvent();
// Define callback used to determine whether or not to short-circuit
$shortCircuit = function ($r) use ($event) {
if ($r instanceof ResponseInterface) {
return true;
}
if ($event->getError()) {
return true;
}
return false;
};
// Trigger route event
$result = $events->trigger(MvcEvent::EVENT_ROUTE, $event, $shortCircuit);
if ($result->stopped()) {
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setTarget($this);
$events->trigger(MvcEvent::EVENT_FINISH, $event);
return $response;
}
if ($event->getError()) {
return $this->completeRequest($event);
}
return $event->getResponse();
}
if ($event->getError()) {
return $this->completeRequest($event);
}
// Trigger dispatch event
$result = $events->trigger(MvcEvent::EVENT_DISPATCH, $event, $shortCircuit);
// Complete response
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setTarget($this);
$events->trigger(MvcEvent::EVENT_FINISH, $event);
return $response;
}
$response = $this->getResponse();
$event->setResponse($response);
return $this->completeRequest($event);
}
это событие-действие: вы понятия не имеете, глядя на код, из которого будут использоваться маршрутизатор, диспетчер и визуализатор, вы знаете только, что эти события будут инициированы. Вы можете подключить практически любой совместимый компонент для прослушивания и обработки событий. Между компонентами нет прямой связи.
но, есть одна важная вещь, чтобы отметить: это уровень представления (контроллер + вид). Уровень домена действительно может управляться событиями, но это не относится почти ко всем приложениям, которые вы видите там. ** Есть смесь между управляемыми событиями и запросами:
// albums controller
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->albumsService->getAlbumsFromArtist('Joy Division'),
));
}
компонент контроллера не управляется событиями. Он напрямую взаимодействует с компонентом service. вместо этого службы должны подписаться на события, поднятые контроллерами, который является частью уровня представления. (Я укажу ссылки на то, что будет моделью домена, управляемой событиями, в конце этого ответа).
Symfony 2
теперь давайте рассмотрим то же самое на Symfony2 Приложения/FrontController: \В Symfony\Компонент\HttpKernel\HttpKernel
он действительно имеет основные события во время запроса:Symfony\Component\HttpKernel\KernelEvents
/**
* Handles a request to convert it to a response.
*
* Exceptions are not caught.
*
* @param Request $request A Request instance
* @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
*
* @return Response A Response instance
*
* @throws \LogicException If one of the listener does not behave as expected
* @throws NotFoundHttpException When controller cannot be found
*/
private function handleRaw(Request $request, $type = self::MASTER_REQUEST)
{
// request
$event = new GetResponseEvent($this, $request, $type);
$this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
if ($event->hasResponse()) {
return $this->filterResponse($event->getResponse(), $request, $type);
}
// load controller
if (false === $controller = $this->resolver->getController($request)) {
throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". Maybe you forgot to add the matching route in your routing configuration?', $request->getPathInfo()));
}
$event = new FilterControllerEvent($this, $controller, $request, $type);
$this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event);
$controller = $event->getController();
// controller arguments
$arguments = $this->resolver->getArguments($request, $controller);
// call controller
$response = call_user_func_array($controller, $arguments);
// view
if (!$response instanceof Response) {
$event = new GetResponseForControllerResultEvent($this, $request, $type, $response);
$this->dispatcher->dispatch(KernelEvents::VIEW, $event);
if ($event->hasResponse()) {
$response = $event->getResponse();
}
if (!$response instanceof Response) {
$msg = sprintf('The controller must return a response (%s given).', $this->varToString($response));
// the user may have forgotten to return something
if (null === $response) {
$msg .= ' Did you forget to add a return statement somewhere in your controller?';
}
throw new \LogicException($msg);
}
}
return $this->filterResponse($response, $request, $type);
}
но помимо того, что он "способен к событиям", он напрямую взаимодействует с компонентом ControllerResolver, поэтому он не полностью управляется событиями с начала процесса запроса, хотя он запускает некоторые события и позволяет некоторым компонентам быть подключаемыми (что не относится к ControllerResolver, который вводится в качестве параметра конструктора).
вместо этого, чтобы быть полностью управляемым событиями компонентом, он должен быть, как в компоненте приложения ZF2:
// Trigger dispatch event
$result = $events->trigger(MvcEvent::EVENT_DISPATCH, $event, $shortCircuit);
Прадо
у меня недостаточно времени, чтобы исследовать исходный код, но сначала он не кажется встроенным в твердый путь. В любом случае, что такое контроллер на MVC-подобных фреймворках, Prado называет его TPage (не уверен пока):
http://www.pradosoft.com/demos/blog-tutorial/?page=Day3.CreateNewUser
и он действительно напрямую связывается с компонентами:
class NewUser extends TPage
{
/**
* Checks whether the username exists in the database.
* This method responds to the OnServerValidate event of username's custom validator.
* @param mixed event sender
* @param mixed event parameter
*/
public function checkUsername($sender,$param)
{
// valid if the username is not found in the database
$param->IsValid=UserRecord::finder()->findByPk($this->Username->Text)===null;
}
[...]
}
Я понимаю, что TPage
является прослушивателем событий и может быть подключаемым. Но это не делает вашу модель домена управляемой событиями. Поэтому я думаю, что в какой-то степени это ближе к предложению ZF2.
событийная примеры
чтобы закончить этот длинный ответ, вот что будет иметь полномасштабное приложение, управляемое событиями:
развязка приложений с событиями доменов http://www.whitewashing.de/2012/08/25/decoupling_applications_with_domain_events.html
событие поиске http://martinfowler.com/eaaDev/EventSourcing.html
Шаблон События Домена http://martinfowler.com/eaaDev/DomainEvent.html
событие Сотрудничество http://martinfowler.com/eaaDev/EventCollaboration.html
Перехват События http://martinfowler.com/bliki/EventInterception.html
Конечная Точка Сообщения http://www.enterpriseintegrationpatterns.com/MessageEndpoint.html
... и так далее
PHP не является апатридом, HTTP. Проще говоря, мы, по сути, построили слой поверх безгосударственной технологии, на которой мы можем реализовать государственные проекты. Взятые вместе, PHP и ваше хранилище данных имеют все инструменты, необходимые для создания дизайна приложения на основе шаблонов, управляемых событиями, посредством токенизации сеансов.
в очень обобщенном виде вы можете думать о HTTP как о том, что для интернета BIOS был для настольных компьютеров. На самом деле, возьмите это еще немного, и вы легко увидите неявный, управляемый событиями характер сети. Вы сказали: "это не событие, а совершенно новый запрос", и я возвращаюсь с " совершенно новым запросом is событие", и я имею в виду, что в Схема смысле этого слова. Он имеет конкретное семантическое значение, связанное с взаимодействием пользователя с вашим приложением.
по существу, через шаблоны, такие как MVC и Front Controller (и по механизму http cookies и PHP сеансы), мы просто восстанавливаем состояние сеанса, а затем реагируем на событие, соответствующим образом изменяя это состояние.
Мне нравится созерцать сущность покоя: передача репрезентативного состояния... но я бы добавил, что мы не должны забывать о неявном подразумевании, что состояние передается только тогда, когда произошло событие UI. Таким образом, мы поддерживаем контракты с HTTP, которые мы "говорим" только в "репрезентативных состояниях" нашей модели (т. е. документа, JSON и т. д.), Но это только наши диалект. Другие системы выбирают говорить в координатах холста, db сигнала, etc.
редактировать/больше мыслей
поэтому я размышлял над этим некоторое время, и я думаю, что есть концепция, которая иллюстрирует немного двусмысленности при обсуждении этих шаблонов в области PHP через HTTP: determinism. В частности, после получения запроса путь выполнения PHP является детерминированным, и именно поэтому чрезвычайно сложно рассматривать " управляемый событиями" архитектура в PHP. Я считаю, что мы должны рассмотреть один уровень выше, чем PHP, до более крупного "сеанса" взаимодействия с пользователем.
в настольных вычислениях мы используем runloops и контекст состояния для "ожидания" событий. Однако я буду утверждать, что интернет на самом деле является улучшением по сравнению с этой архитектурой (в большинстве случаев), но в конечном итоге тот же шаблон. Вместо состояния runloop и бесконечной длительности мы загружаем наше состояние когда событие происходит и затем обработать это событие. И вместо того, чтобы просто хранить это состояние в памяти и ждать следующего события, мы архивируем это состояние и закрываем ресурсы. Его можно считать менее эффективным в одном смысле (что нам нужно загружать состояние при каждом "событии"), но его также можно назвать более эффективным в том, что никогда состоянии ожидания в памяти без причины. Мы загружаем только состояние, которое фактически потребленной/манипулировать
Так в этом кстати, подумайте о PHP через HTTP как о событии, управляемом в макрос уровень, при этом будучи уверенным, что любое данное выполнение действительно детерминировано и на самом деле не управляется событиями. Однако мы реализуем шаблон front-controller и MVC, чтобы предоставить разработчикам приложений знакомые структура даже управляемых Крюков. Когда вы работаете с достойной структурой, вы просто говорите: "Я хочу знать, когда пользователь регистрируется, и пользователь должен быть доступен меня модифицировать в то время". Это событийное развитие. Вас не должно беспокоить, что фреймворк загрузил среду для (почти) единственной цели вызова вашего крючка (по сравнению с более традиционным представлением о том, что среда уже была там, и Вы были просто уведомления событие). Это то, что значит разрабатывать PHP с учетом событий. Контроллеры определяют (на основе запроса), какие событие происходит и использует whichever механизм он предназначен для использования (т. е. шаблон наблюдателя, архитектура крючка и т. д.), чтобы позволить вашему коду обрабатывать событие, реагировать на событие или любую номенклатуру, наиболее подходящую для семантики вашей конкретной структуры.