{"action":"created","issue":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/2","labels_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/2/comments","events_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/2/events","html_url":"https://github.com/zendframework/zend-eventmanager/pull/2","id":77764959,"number":2,"title":"Refactor","user":{"login":"bakura10","id":1198915,"avatar_url":"https://avatars.githubusercontent.com/u/1198915?v=3","gravatar_id":"","url":"https://api.github.com/users/bakura10","html_url":"https://github.com/bakura10","followers_url":"https://api.github.com/users/bakura10/followers","following_url":"https://api.github.com/users/bakura10/following{/other_user}","gists_url":"https://api.github.com/users/bakura10/gists{/gist_id}","starred_url":"https://api.github.com/users/bakura10/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bakura10/subscriptions","organizations_url":"https://api.github.com/users/bakura10/orgs","repos_url":"https://api.github.com/users/bakura10/repos","events_url":"https://api.github.com/users/bakura10/events{/privacy}","received_events_url":"https://api.github.com/users/bakura10/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/labels/awaiting%20author%20updates","name":"awaiting author updates","color":"e11d21"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":28,"created_at":"2015-05-18T18:54:14Z","updated_at":"2015-07-03T16:47:20Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/pulls/2","html_url":"https://github.com/zendframework/zend-eventmanager/pull/2","diff_url":"https://github.com/zendframework/zend-eventmanager/pull/2.diff","patch_url":"https://github.com/zendframework/zend-eventmanager/pull/2.patch"},"body":"Hi everyone,\r\n\r\nPS: Everyone is free to fork my branch and submit PR to it!\r\n\r\n## Motivation\r\n\r\nEvent manager has always been, with service manager, the slowest parts of ZF2, but the most widely used one internally. It was therefore highly important to make them faster.\r\n\r\nAlso, the event manager was a complex piece of software with a lot of obscure features, a strange shared manager concept and complex signatures.\r\n\r\n## Breaking changes\r\n\r\n### Massive performance improvements\r\n\r\nI copy-paste some of the benchmarks I've made (the PHP7 build was an old one, so expect at least 10-15% improvments on PHP7):\r\n\r\nZF2 EVM\r\n\r\nPHP 5.6\r\n\r\n    Bench\\EventManagerBenchmark\r\n    Method Name          Iterations    Average Time      Ops/second\r\n    ------------------  ------------  --------------    -------------\r\n    attach20Listeners : [1,000     ] [0.0005693485737] [1,756.39326]\r\n    trigger20Listeners: [1,000     ] [0.0010452888012] [956.67341]\r\n\r\n\r\nPHP 7\r\n\r\n    Bench\\EventManagerBenchmark\r\n    Method Name          Iterations    Average Time      Ops/second\r\n    ------------------  ------------  --------------    -------------\r\n    attach20Listeners : [1,000     ] [0.0000875046253] [11,427.96734]\r\n    trigger20Listeners: [1,000     ] [0.0001518340111] [6,586.13965]\r\n\r\n\r\n\r\nZF3 EVM\r\n\r\nPHP 5.6\r\n\r\n    Bench\\EventManagerBenchmark\r\n    Method Name          Iterations    Average Time      Ops/second\r\n    ------------------  ------------  --------------    -------------\r\n    attach20Listeners : [1,000     ] [0.0001252155304] [7,986.22980]\r\n    trigger20Listeners: [1,000     ] [0.0002773256302] [3,605.86939]\r\n\r\nPHP 7\r\n\r\n    Bench\\EventManagerBenchmark\r\n    Method Name          Iterations    Average Time      Ops/second\r\n    ------------------  ------------  --------------    -------------\r\n    attach20Listeners : [1,000     ] [0.0000128707886] [77,695.31713]\r\n    trigger20Listeners: [1,000     ] [0.0000429670811] [23,273.63123]\r\n    \r\n    \r\n### No more shared event manager\r\n\r\nI've explain myself why I think the shared event manager was a bad idea (although @ocramius tried to show me the contrary, I think the event manager should stay simple as introduced in this PR).\r\n\r\nAs I used EVM in my app, I realized I ONLY used the Shared event manager. But the SEM is SLOW AS HELL and complex (because of identifiers, expensive merging...). I think that in most use cases, people should have a global EVM used throughout their applications, and have more precise event name.\r\n\r\n### Simplifications\r\n\r\nPreviously, trigger and triggerUntil were very complex. Depending on the order and types of parameters, you could use it in a LOT of different ways. Now everything has been enforced in interfaces, so there is one possible use case, which make things clearer and more efficient (less checks).\r\n\r\n### Event no longer has name\r\n\r\nI've simplified the `EventInterface` so that it no longer has a `getName` method. I'm not against reverting it, but to me, we should trigger event like this:\r\n\r\n```php\r\n$evm->trigger('event.name', $eventObject);\r\n```\r\n\r\nAs an event object could be used for various event names, I think it makes more sense to be used like this (and avoid to re-add logic to check if the first parameter is a string or object... that kind of things).\r\n\r\n`propagationIsStopped` has been renamed to `isPropagationStopped`.    \r\n\r\n### Lazy listeners\r\n\r\nOne main issue with ZF2 was the inability to have lazy listeners. This means taht when you attach listeners, they are created, with all their dependencies, on every requests, even if you don't need them.\r\n\r\nFrom my app, this can add a non-negligible overhead, and solutions like proxies are annoying to setup.\r\n\r\n\r\n\r\nSome example usage:\r\n\r\n```php\r\n<?php\r\n    // The idea is that in ZF3, there will be one \"application-wide\" event manager registered. Nothing prevents you to\r\n    // create your own local event manager, but to replicate the shared manager behaviour, you should retrieve the\r\n    // application-wide evm\r\n\r\n    // Attaching a simple listener:\r\n\r\n    $eventManager = new EventManager();\r\n    $eventManager->attach('foo', function() {}, $priority);\r\n\r\n    // Triggering a listener\r\n    $eventManager->trigger('foo', new Event());\r\n\r\n    // Triggering a listener with a callable that will stop propagation if return to true\r\n    $eventManager->triggerUntil('foo', new Event(), function() {});\r\n\r\n    // Attaching to wildcard\r\n    $eventManager->attach('*', function() {});\r\n\r\n    // Attaching a listener and detaching it\r\n    $listener = $eventManager->attach('foo', function() {});\r\n    $eventManager->detach('foo', $listener);\r\n\r\n    // Detaching all listeners from a given event\r\n    $eventManager->detach('foo');\r\n\r\n\r\n    // Using listener aggregate to aggregate multiple events, lazily\r\n    class MyListenerAggregate implements ListenerAggregateInterface\r\n    {\r\n        public static function attachAggregate(EventManager $evm)\r\n        {\r\n            // No more confusion of getting the shared manager. Note the method is static, and\r\n            // that we pass a \"spec\" without instantiating the listener, as it will be created only\r\n            // on demand\r\n            $evm->attach('foo', [static::class, 'myMethod']);\r\n        }\r\n\r\n        public function myMethod(Event $event)\r\n        {\r\n\r\n        }\r\n    }\r\n\r\n    // In the module class\r\n    $evm = $serviceLocator->get(EventManager::class);\r\n    MyListenerAggregate::attachAggregate($evm); // Maybe should be called \"bind\" instad of attachAggregate\r\n\r\n    // No more identifiers, no more SEM... Of course, events must now be scoped, so no \"created\" event anymore,\r\n    // but \"user.created\", \"application.dispatch\", \"controller.dispatch\"...\r\n\r\n?>\r\n```"},"comment":{"url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/comments/118391340","html_url":"https://github.com/zendframework/zend-eventmanager/pull/2#issuecomment-118391340","issue_url":"https://api.github.com/repos/zendframework/zend-eventmanager/issues/2","id":118391340,"user":{"login":"weierophinney","id":25943,"avatar_url":"https://avatars.githubusercontent.com/u/25943?v=3","gravatar_id":"","url":"https://api.github.com/users/weierophinney","html_url":"https://github.com/weierophinney","followers_url":"https://api.github.com/users/weierophinney/followers","following_url":"https://api.github.com/users/weierophinney/following{/other_user}","gists_url":"https://api.github.com/users/weierophinney/gists{/gist_id}","starred_url":"https://api.github.com/users/weierophinney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weierophinney/subscriptions","organizations_url":"https://api.github.com/users/weierophinney/orgs","repos_url":"https://api.github.com/users/weierophinney/repos","events_url":"https://api.github.com/users/weierophinney/events{/privacy}","received_events_url":"https://api.github.com/users/weierophinney/received_events","type":"User","site_admin":false},"created_at":"2015-07-03T16:47:20Z","updated_at":"2015-07-03T16:47:20Z","body":"> But I can't weight it against keeping BC, because currently I don't know what ZF 3.0 really means. Is it just the component split? Will the mvc component be replaced by middleware in the long run? How will MVC + modules + EVM + ServiceManager + middleware work together?\r\n> Answers to these questions would help, because if zend-mvc is refactored anyway why not refactor zend-eventmanager too?\r\n\r\nAs noted on the ZF3 roadmap post, the following are the key components of ZF3:\r\n\r\n- Component split (already done!)\r\n- PSR-7 implementation and integration (implementation is done; integration is in progress)\r\n- *Addition* of a middleware implementation (done) and a slim, limited microframework built on it (in progress)\r\n- Performance/consistency improvements to the *current* MVC (which include proposed refactors to the SM and EM primarily, but also a few other components).\r\n\r\nEssentially, the ZF2 MVC will be retained in a *mostly* BC way to ease migration. However, it will be PSR-7 middleware-aware to allow composing middleware from other projects and components. Additionally, we'll be providing middleware wrappers around ZF1 and ZF2 bootstraps to allow invoking them as middleware (which allows segregating different application aspects, and migrating from the ZF1 and ZF2 MVC to middleware-based solutions).\r\n\r\nBut, again, we are not proposing major changes to the current MVC. Many people are building successful, complex applications using it, and are happy with the solution; we want to continue enabling these solutions, without providing an onerous upgrade path."}}