tipos sinóptico secuencial que programación programacion paradigmas orientada objetos lenguaje historia eventos ejemplos cuadro conclusion php oop design-patterns signals event-driven

php - sinóptico - que es un lenguaje de programacion secuencial



PHP: ¿Estoy mezclando la programación dirigida por eventos con interfaces sensibles a señales(señal y ranuras/patrón de observador)? (2)

He visto a mucha gente decir que Symfony2, Zend Framework 2 y otros están impulsados ​​por eventos.

En el mundo de los escritorios, por programación basada en eventos entiendo que la aplicación notificará a sus observadores cada vez que cambie su estado.

Como las aplicaciones PHP son sin estado, no hay forma de hacerlo. IE Tener observadores atados a la vista observando cambios mientras el usuario usa la interfaz. En su lugar, necesita un nuevo proceso de solicitud para actualizar la vista. Entonces, no es un evento sino una solicitud completamente nueva .

Por otro lado, hay un concepto similar: arquitectura impulsada por eventos.

Aquí puedes leer ambos:

http://en.wikipedia.org/wiki/Event-driven_programming

http://en.wikipedia.org/wiki/Event-driven_architecture

Y aquí el otro:

http://en.wikipedia.org/wiki/Signal_programming

Una señal es una notificación a un proceso que ocurrió un evento. Las señales a veces se describen como interrupciones de software. Las señales son análogas a las interrupciones de hardware porque interrumpen el flujo normal de ejecución de un programa; en la mayoría de los casos, no es posible predecir exactamente cuándo llegará una señal.

  • Descripción de la etiqueta Stackoverflow [singals]

Por otra parte, lo que solía llamar evento-driven parece estar más relacionado con las señales y el patrón de tragamonedas introducido por Qt (implementación del patrón observador)

Como ejemplo, está el Marco del Prado que dice ser impulsado por eventos:

http://www.pradosoft.com/demos/quickstart/?page=Fundamentals.Applications (Application Lifecycles section)

http://www.pradosoft.com/docs/manual/System/TApplication.html#methodonEndRequest

IIRC, esto no es una aplicación impulsada por eventos, sino simplemente los ganchos de conexión (señales y ranuras) utilizados por las clases que implementan la observable Interface . Quiero decir, considerando la forma en que las aplicaciones de escritorio usan eventos y la forma en que las aplicaciones sin estado usan eventos (como plug-in): los primeros eventos de uso para toda la aplicación, incluidas las vistas, la última solo para las operaciones del lado del servidor.

Uno está más relacionado con la programación orientada a aspectos (con señales y ranuras) y el otro no está específicamente vinculado a preocupaciones transversales / AOP. En otras palabras, está más relacionado con el estado de la aplicación.

Entonces, ¿cuál es, de hecho, la relación entre estos términos y cómo difieren entre sí?

  1. Programación orientada a eventos
  2. Arquitectura orientada a eventos
  3. Signals and Slots Pattern

¿Son estos términos solo patrones genéricos? Por lo tanto, todo lo que implementa el patrón del observador puede considerarse impulsado por eventos.

ACTUALIZAR

Zend Framework 2

El artículo sobre AOP que he vinculado anteriormente ( http://mwop.net/blog/251-Aspects,-Filters,-and-Signals,-Oh,-My!.html ) fue escrito por Matthew Weier O''Phinney ( ZF Leader). IIRC, no tiene menciones sobre "conducido por eventos", solo señales y máquinas tragamonedas.

Symfony 2

La descripción del componente Symfony2 EventDispatcher no tiene menciones sobre aplicaciones "controladas por eventos": http://symfony.com/doc/current/components/event_dispatcher/introduction.html. Solo contiene referencias a "Eventos" (que, de hecho, son manejados por Signal and Slots).

Ambos marcos parecen usar el patrón de filtro de interceptación dentro de la señal y las ranuras para manejar eventos síncronos durante el proceso de solicitud.


PHP no es sin estado, HTTP es. Para decirlo simplemente, básicamente hemos construido una capa sobre una tecnología sin estado sobre la cual podemos implementar diseños con estado. En conjunto, PHP y su almacén de datos de elección tienen todas las herramientas que necesitan para crear un diseño de aplicaciones basado en patrones de eventos mediante la tokenización de sesiones.

De una manera muy generalizada, puede pensar que HTTP es para la web lo que ha sido el BIOS para computación de escritorio. De hecho, lleve esto un poco más allá y podrá ver fácilmente la naturaleza implícita de la web impulsada por eventos. Dijiste "no es un evento, sino una solicitud completamente nueva", y vuelvo con "una solicitud completamente nueva es un evento", y me refiero a eso en el sentido del patrón de diseño de la palabra. Tiene un significado semántico concreto relacionado con la interacción de su usuario con su aplicación.

Básicamente, a través de patrones como MVC y Front Controller (y por el mecanismo de cookies HTTP y sesiones de PHP), simplemente restauramos el estado de la sesión y luego respondemos al evento, modificando ese estado en consecuencia.

Me gusta contemplar la esencia de REST: Representational State Transfer ... pero agregaría que no debemos olvidar la implicación implícita de que el estado solo se transfiere cuando se produce un evento de UI. Así que mantenemos los contratos que tenemos con HTTP de que "hablamos" solo en "Estados representativos" de nuestro modelo (es decir, un documento, JSON, etc.), pero ese es solo nuestro dialecto. Otros sistemas eligen hablar en coordenadas de lienzo, señal db, etc.

editar / más pensamientos

Así que lo he estado reflexionando durante un tiempo y creo que hay un concepto que ilustra un poco la ambigüedad cuando se discuten estos patrones en el ámbito de PHP a través de HTTP: el determinismo. Específicamente, una vez que se recibe una solicitud, la ruta de la ejecución de PHP es determinista, y esta es exactamente la razón por la cual es muy difícil considerar una arquitectura "basada en eventos" en PHP. Mi noción es que deberíamos considerar un nivel más alto que PHP, para la "sesión" de interacción más grande con el usuario.

En computación de escritorio, usamos runloops y un contexto estatal para "esperar" eventos. Sin embargo, voy a argumentar que la web es en realidad una mejora sobre esta arquitectura (en la mayoría de los casos), pero en última instancia, el mismo patrón . En lugar de un estado runloop y duración infinita, iniciamos nuestro estado cuando ocurre un evento y luego procesamos ese evento. Y en lugar de simplemente mantener ese estado en la memoria y esperar el próximo evento, archivamos ese estado y cerramos los recursos. Podría considerarse menos eficiente en un sentido (que tenemos que cargar el estado en cada "evento"), pero también podría llamarse más eficiente en el sentido de que nunca hay estado inactivo en la memoria sin ningún motivo. Solo cargamos estado que en realidad se está consumiendo / manipulando

Entonces, de esta manera, piense en PHP a través de HTTP como impulsado por eventos en el nivel macro , mientras descansa seguro de que cualquier ejecución dada es de hecho determinista y en realidad no impulsada por ningún evento. Sin embargo, implementamos un controlador frontal y un patrón MVC para que podamos proporcionarles a los desarrolladores de aplicaciones la estructura familiar de incluso los ganchos accionados. Cuando trabajas con un marco decente, simplemente dices "Quiero saber cuándo se registra un usuario y el usuario debería estar disponible para modificarlo en ese momento". Este es un desarrollo impulsado por eventos. No debería preocuparle que el marco haya arrancado el entorno para (casi) el único propósito de llamar a su gancho (frente a la noción más tradicional de que el entorno ya estaba allí y que simplemente se le notificó un evento). Esto es lo que significa desarrollar PHP de forma orientada a eventos. Los controladores determinan (según la solicitud) qué evento está ocurriendo y utilizan el mecanismo que está diseñado para usar (es decir, patrón de observador, arquitectura de gancho, etc.) para permitir que su código maneje el evento, responda al evento o cualquier nomenclatura es el más apropiado para la semántica de su marco particular.


Descargo de responsabilidad: Es una respuesta larga, pero creo que vale la pena leerla con todas sus referencias. Y en mi humilde opinión conduce a una respuesta concluyente.

He estado luchando sobre estos temas en los últimos días y, si he leído todo correctamente, la respuesta es:

¡Impulsado por eventos! == Basado en solicitudes

"[...] Encuentro esta la diferencia más interesante en la colaboración de eventos, para parafrasear a Jon Udell: el software dirigido por solicitudes habla cuando se le habla, el software impulsado por eventos habla cuando tiene algo que decir.

Una consecuencia de esto es que la responsabilidad de administrar los cambios de estado. En la colaboración solicitada, se esfuerza por garantizar que cada dato tenga un hogar, y lo busca desde ese hogar si lo desea. Esta casa es responsable de la estructura de los datos, cuánto tiempo está almacenada y cómo acceder a ella. En el escenario de colaboración del evento, la fuente de nuevos datos es bienvenida para olvidar los datos en el segundo momento en que pasa a su punto final del mensaje ".

Martin Fowler - Colaboración de eventos (sección Consultas)

Sobre la base de esa afirmación, IIRC, los marcos de PHP modernos implementan el Observer Pattern + Intercepting Filters + Singal and Slots, para activar algunos eventos durante el ciclo de solicitud.

Pero, a pesar del hecho de que adopta algunas ideas de arquitecturas basadas en eventos, no parece apoyar que todo el framework esté basado en eventos (es decir, Symfony2 es un framewrok impulsado por eventos).

Estamos acostumbrados a dividir programas en múltiples componentes que colaboran juntos. (Estoy usando deliberadamente la palabra vaga "componente" ya que en este contexto me refiero a muchas cosas: incluir objetos dentro de un programa y múltiples procesos que se comunican a través de una red). La forma más común de hacerlos colaborar es un estilo de solicitud / respuesta . Si un objeto de cliente quiere algunos datos de un objeto de vendedor, invoca un método en el objeto de vendedor para pedirle esa información.

Otro estilo de colaboración es Event Collaboration. En este estilo , nunca tiene un componente que le pida a otro que haga nada , sino que cada componente señala un evento cuando algo cambia. Otros componentes escuchan ese evento y reaccionan como lo deseen. El patrón de observador bien conocido es un ejemplo de colaboración de eventos.

Martin Fowler - Enfoque en eventos (sección: Uso de eventos para colaborar)

Creo que las aplicaciones PHP están más orientadas a los eventos que a las solicitudes solo cuando el foco está en los eventos . Si esas aplicaciones / frameworks solo están usando eventos para preocupaciones transversales (AOP), entonces no están basadas en eventos. De la misma manera, no lo llamarías basado en pruebas o impulsado por el dominio solo porque tienes algunos objetos de dominio y pruebas de unidades.

Ejemplos del mundo real

He escogido algunos ejemplos para mostrar por qué esos marcos no están completamente orientados a eventos. A pesar de los eventos de AOP, todo se basa en solicitudes :

Nota: Aunque puede adaptarse para ser controlado por eventos

Zend Framework 2

Examinemos el componente / Zend / Mvc / Application :

Implementa el / Zend / EventManager / EventManagerAwareInterface y se basa en el / Zend / Mvc / MvcEvent que describe los posibles eventos:

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''; // [...] }

El componente / Zend / Mvc / Application en sí mismo es impulsado por eventos porque no se comunica directamente con los otros componentes, sino que simplemente desencadena eventos:

/** * 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); }

Esto depende de los eventos: no tiene ni idea de cómo usar el enrutador, el despachador y el procesador de vistas, solo sabe que esos eventos se activarán. Puede conectar casi cualquier componente compatible para escuchar y procesar los eventos. No hay comunicación directa entre los componentes.

Pero, hay una cosa importante a tener en cuenta: esta es la capa de presentación (Controller + View). La capa de dominio puede ser controlada por eventos, pero ese no es el caso de casi todas las aplicaciones que ves por ahí. ** Hay una mezcla entre impulsada por eventos y impulsada por solicitudes:

// albums controller public function indexAction() { return new ViewModel(array( ''albums'' => $this->albumsService->getAlbumsFromArtist(''Joy Division''), )); }

El componente del controlador no está controlado por eventos. Se comunica directamente con el componente de servicio. En su lugar, los servicios deberían suscribirse a eventos resueltos por controladores , que es parte de la capa de presentación. (Señalaré las referencias sobre lo que sería un modelo de dominio basado en eventos al final de esta respuesta).

Symfony 2

Ahora examinemos lo mismo en la aplicación Symfony2 / FrontController: / Symfony / Component / HttpKernel / HttpKernel

De hecho, tiene los eventos principales durante la solicitud: 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); }

Pero además de ser "capaz de eventos", se comunica directamente con el componente ControllerResolver, por lo tanto no es totalmente controlado por eventos desde el comienzo del proceso de solicitud, aunque desencadena algunos eventos y permite que algunos componentes sean conectables (lo cual no es el caso del ControllerResolver que se inyecta como un parámetro de constructor).

En cambio, para ser un componente totalmente orientado a eventos, debe ser como en el componente de aplicación ZF2:

// Trigger dispatch event $result = $events->trigger(MvcEvent::EVENT_DISPATCH, $event, $shortCircuit);

Prado

No tengo tiempo suficiente para investigar el código fuente, pero al principio no parece estar construido de manera SÓLIDA . De cualquier manera, ¿qué es un controlador en marcos MVC-por igual, Prado lo llama un TPage (No estoy seguro todavía):

http://www.pradosoft.com/demos/blog-tutorial/?page=Day3.CreateNewUser

Y de hecho se comunica directamente con los componentes:

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; } [...] }

Entiendo que el TPage es un oyente de eventos y puede ser conectable. Pero no hace que su modelo de dominio sea impulsado por eventos. Así que creo que, en cierta medida, está más cerca de la propuesta de ZF2.

Ejemplos impulsados ​​por eventos

Para finalizar esta larga respuesta, esto es lo que una aplicación impulsada por eventos en toda regla tendría:

Desacoplamiento de aplicaciones con eventos de dominios http://www.whitewashing.de/2012/08/25/decoupling_applications_with_domain_events.html

Aprovisionamiento de eventos http://martinfowler.com/eaaDev/EventSourcing.html

Patrón de evento de dominio http://martinfowler.com/eaaDev/DomainEvent.html

Colaboración de eventos http://martinfowler.com/eaaDev/EventCollaboration.html

Intercepción de eventos http://martinfowler.com/bliki/EventInterception.html

Punto final del mensaje http://www.enterpriseintegrationpatterns.com/MessageEndpoint.html

... y así