From d5c048cdfdb678bdd8d6f6bdeef3d6249d15b581 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:15:20 -0400 Subject: [PATCH 01/11] Initial working codebase, PHP8 --- .gitattributes | 3 + .github/workflows/ci.yaml | 17 +++- .gitignore | 2 + CHANGELOG.md | 1 - README.md | 9 +- composer.json | 13 ++- doc/01-api.md | 22 ++--- doc/02-plugin-system.md | 16 ++-- phpunit.xml.dist | 32 ++++--- src/EventEmitterInterface.php | 40 ++++++-- src/EventEmitterTrait.php | 52 ++++++---- tests/EventEmitterTest.php | 173 ++++++++++++++++++---------------- 12 files changed, 229 insertions(+), 151 deletions(-) diff --git a/.gitattributes b/.gitattributes index 8e493b8..b2b76c3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,6 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text eol=lf + /.github export-ignore /doc export-ignore /examples export-ignore diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dfc50e4..9d6d848 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,9 @@ name: CI + on: push: pull_request: + jobs: supported-versions-matrix: name: Supported Versions Matrix @@ -9,9 +11,10 @@ jobs: outputs: version: ${{ steps.supported-versions-matrix.outputs.version }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - id: supported-versions-matrix uses: WyriHaximus/github-action-composer-php-versions-in-range@v1 + test: name: Run Tests and Code Quality on PHP ${{ matrix.php }} runs-on: ubuntu-latest @@ -23,28 +26,34 @@ jobs: php: ${{ fromJson(needs.supported-versions-matrix.outputs.version) }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + - name: Setup PHP, extensions and composer with shivammathur/setup-php uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: mbstring, ctype, iconv, bcmath, filter, json coverage: xdebug, pcov - tools: composer:v1 + tools: composer:v2 + - name: Get composer cache directory id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Get composer action hash id: composer-action-hash run: printf "::set-output name=hash::%s" $(echo -n "${{ matrix.composer }}" | sha512sum) + - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer-${{ steps.composer-action-hash.outputs.hash }} + - name: Install Composer dependencies run: composer install --no-progress --no-interaction --no-suggest --optimize-autoloader --ansi + - name: Test run: | ./vendor/bin/phpunit --coverage-text diff --git a/.gitignore b/.gitignore index 987e2a2..48a56c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ composer.lock vendor +.phpunit.result.cache +.phpunit.cache \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a34a4db..7efb47b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ CHANGELOG ========= - * v3.0.1 (2017-07-23) * Resolved regression introduced in once listeners in v3.0.0 [#49](https://github.com/igorw/evenement/pull/49) diff --git a/README.md b/README.md index 455dd22..9967ada 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ It is very strongly inspired by the [EventEmitter](https://nodejs.org/api/events The recommended way to install Événement is [through composer](http://getcomposer.org). By running the following command: +```bash $ composer require evenement/evenement +``` ## Usage @@ -33,7 +35,7 @@ $emitter = new Evenement\EventEmitter(); ```php on('user.created', function (User $user) use ($logger) { +$emitter->on('user.created', static function (User $user) use ($logger): void { $logger->log(sprintf("User '%s' was created.", $user->getLogin())); }); ``` @@ -42,7 +44,7 @@ $emitter->on('user.created', function (User $user) use ($logger) { ```php removeListener('user.created', function (User $user) use ($logger) { +$emitter->removeListener('user.created', static function (User $user) use ($logger): void { $logger->log(sprintf("User '%s' was created.", $user->getLogin())); }); ``` @@ -56,8 +58,9 @@ $emitter->emit('user.created', [$user]); Tests ----- - +```bash $ ./vendor/bin/phpunit +``` License ------- diff --git a/composer.json b/composer.json index 5444d93..da6ffa0 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,11 @@ { "name": "evenement/evenement", "description": "Événement is a very simple event dispatching library for PHP", - "keywords": ["event-dispatcher", "event-emitter"], "license": "MIT", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], "authors": [ { "name": "Igor Wiedler", @@ -10,10 +13,10 @@ } ], "require": { - "php": ">=7.0" + "php": ">=8.0" }, "require-dev": { - "phpunit/phpunit": "^9 || ^6" + "phpunit/phpunit": "^10 || ^11" }, "autoload": { "psr-4": { @@ -24,6 +27,8 @@ "psr-4": { "Evenement\\Tests\\": "tests/" }, - "files": ["tests/functions.php"] + "files": [ + "tests/functions.php" + ] } } diff --git a/doc/01-api.md b/doc/01-api.md index 17ba333..307487f 100644 --- a/doc/01-api.md +++ b/doc/01-api.md @@ -6,14 +6,14 @@ define an interface that extends the emitter and implicitly defines certain events to be emitted, or if you want to type hint an `EventEmitter` to be passed to a method without coupling to the specific implementation. -## on($event, callable $listener) +## on(?string $event, callable $listener): static; Allows you to subscribe to an event. Example: ```php -$emitter->on('user.created', function (User $user) use ($logger) { +$emitter->on('user.created', static function (User $user) use ($logger): void { $logger->log(sprintf("User '%s' was created.", $user->getLogin())); }); ``` @@ -23,7 +23,7 @@ instead of the anonymous function: ```php $loggerSubscriber = new LoggerSubscriber($logger); -$emitter->on('user.created', array($loggerSubscriber, 'onUserCreated')); +$emitter->on('user.created', [$loggerSubscriber, 'onUserCreated']); ``` This has the benefit that listener does not even need to know that the emitter @@ -32,10 +32,10 @@ exists. You can also accept more than one parameter for the listener: ```php -$emitter->on('numbers_added', function ($result, $a, $b) {}); +$emitter->on('numbers_added', static function (int $result, int $a, int $b): void {}); ``` -## once($event, callable $listener) +## once(?string $event, callable $listener): static; Convenience method that adds a listener which is guaranteed to only be called once. @@ -43,12 +43,12 @@ once. Example: ```php -$conn->once('connected', function () use ($conn, $data) { +$conn->once('connected', static function () use ($conn, $data): void { $conn->send($data); }); ``` -## emit($event, array $arguments = []) +## emit(?string $event, array $arguments = []): void; Emit an event, which will call all listeners. @@ -66,7 +66,7 @@ $result = $a + $b; $emitter->emit('numbers_added', [$result, $a, $b]); ``` -## listeners($event) +## listeners(?string $event): array; Allows you to inspect the listeners attached to an event. Particularly useful to check if there are any listeners at all. @@ -75,16 +75,16 @@ Example: ```php $e = new \RuntimeException('Everything is broken!'); -if (0 === count($emitter->listeners('error'))) { +if (0 === \count($emitter->listeners('error'))) { throw $e; } ``` -## removeListener($event, callable $listener) +## removeListener(?string $event, callable $listener): void; Remove a specific listener for a specific event. -## removeAllListeners($event = null) +## removeAllListeners(?string $event = null): void; Remove all listeners for a specific event or all listeners all together. This is useful for long-running processes, where you want to remove listeners in diff --git a/doc/02-plugin-system.md b/doc/02-plugin-system.md index 6a08371..8de95e2 100644 --- a/doc/02-plugin-system.md +++ b/doc/02-plugin-system.md @@ -29,7 +29,7 @@ A plugin class must implement the `PluginInterface`: ```php interface PluginInterface { - function attachEvents(EventEmitterInterface $emitter); + public function attachEvents(EventEmitterInterface $emitter): void; } ``` @@ -38,9 +38,9 @@ emitter. For example: ```php class FooPlugin implements PluginInterface { - public function attachEvents(EventEmitterInterface $emitter) + public function attachEvents(EventEmitterInterface $emitter): void { - $emitter->on('foo', function () { + $emitter->on('foo', static function (): void { echo 'bar!'; }); } @@ -76,7 +76,7 @@ In the code that creates the post, I'll insert the `post.create` event: ```php class PostEvent { - public $post; + public array $post; public function __construct(array $post) { @@ -98,7 +98,7 @@ allowing listeners to change it. The same thing for the `post.render` event: ```php -public function renderPostBody(array $post) +public function renderPostBody(array $post): string { $emitter = $this->emitter; @@ -127,13 +127,13 @@ The `markdown` function represents a markdown to HTML converter. ```php class MarkdownPlugin implements PluginInterface { - public function attachEvents(EventEmitterInterface $emitter) + public function attachEvents(EventEmitterInterface $emitter): void { - $emitter->on('post.create', function (PostEvent $event) { + $emitter->on('post.create', static function (PostEvent $event): void { $event->post['format'] = 'markdown'; }); - $emitter->on('post.render', function (PostEvent $event) { + $emitter->on('post.render', static function (PostEvent $event): void { if (isset($event->post['format']) && 'markdown' === $event->post['format']) { $event->post['body'] = markdown($event->post['body']); } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 43e1793..a7ac001 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,24 +1,28 @@ - - + failOnRisky="true" + failOnWarning="true"> ./tests/ - - + + ./src/ - - + + diff --git a/src/EventEmitterInterface.php b/src/EventEmitterInterface.php index 310631a..00444be 100644 --- a/src/EventEmitterInterface.php +++ b/src/EventEmitterInterface.php @@ -13,10 +13,38 @@ interface EventEmitterInterface { - public function on($event, callable $listener); - public function once($event, callable $listener); - public function removeListener($event, callable $listener); - public function removeAllListeners($event = null); - public function listeners($event = null); - public function emit($event, array $arguments = []); + /** + * Allows you to subscribe to an event. + */ + public function on(?string $event, callable $listener): static; + + /** + * Convenience method that adds a listener which is guaranteed to only be + * called once. + */ + public function once(?string $event, callable $listener): static; + + /** + * Remove a specific listener for a specific event. + */ + public function removeListener(?string $event, callable $listener): void; + + /** + * Remove all listeners for a specific event or all listeners all together. + * + * This is useful for long-running processes, where you want to remove listeners + * in order to allow them to get garbage collected. + */ + public function removeAllListeners(?string $event = null): void; + + /** + * Allows you to inspect the listeners attached to an event. Particularly useful + * to check if there are any listeners at all. + */ + public function listeners(?string $event = null): array; + + /** + * Emit an event, which will call all listeners. + */ + public function emit(?string $event, array $arguments = []): void; } diff --git a/src/EventEmitterTrait.php b/src/EventEmitterTrait.php index 1503429..e65d68e 100644 --- a/src/EventEmitterTrait.php +++ b/src/EventEmitterTrait.php @@ -13,7 +13,6 @@ use InvalidArgumentException; -use function count; use function array_keys; use function array_merge; use function array_search; @@ -22,10 +21,17 @@ trait EventEmitterTrait { - protected $listeners = []; - protected $onceListeners = []; + /** + * @var array> + */ + protected array $listeners = []; - public function on($event, callable $listener) + /** + * @var array> + */ + protected array $onceListeners = []; + + public function on(?string $event, callable $listener): static { if ($event === null) { throw new InvalidArgumentException('event name must not be null'); @@ -40,7 +46,7 @@ public function on($event, callable $listener) return $this; } - public function once($event, callable $listener) + public function once(?string $event, callable $listener): static { if ($event === null) { throw new InvalidArgumentException('event name must not be null'); @@ -55,7 +61,7 @@ public function once($event, callable $listener) return $this; } - public function removeListener($event, callable $listener) + public function removeListener(?string $event, callable $listener): void { if ($event === null) { throw new InvalidArgumentException('event name must not be null'); @@ -63,9 +69,11 @@ public function removeListener($event, callable $listener) if (isset($this->listeners[$event])) { $index = array_search($listener, $this->listeners[$event], true); + if (false !== $index) { unset($this->listeners[$event][$index]); - if (count($this->listeners[$event]) === 0) { + + if (\count($this->listeners[$event]) === 0) { unset($this->listeners[$event]); } } @@ -73,16 +81,18 @@ public function removeListener($event, callable $listener) if (isset($this->onceListeners[$event])) { $index = array_search($listener, $this->onceListeners[$event], true); + if (false !== $index) { unset($this->onceListeners[$event][$index]); - if (count($this->onceListeners[$event]) === 0) { + + if (\count($this->onceListeners[$event]) === 0) { unset($this->onceListeners[$event]); } } } } - public function removeAllListeners($event = null) + public function removeAllListeners(?string $event = null): void { if ($event !== null) { unset($this->listeners[$event]); @@ -97,7 +107,10 @@ public function removeAllListeners($event = null) } } - public function listeners($event = null): array + /** + * @return array>|list<(callable)> + */ + public function listeners(?string $event = null): array { if ($event === null) { $events = []; @@ -107,22 +120,26 @@ public function listeners($event = null): array array_keys($this->onceListeners) ) ); + foreach ($eventNames as $eventName) { $events[$eventName] = array_merge( - isset($this->listeners[$eventName]) ? $this->listeners[$eventName] : [], - isset($this->onceListeners[$eventName]) ? $this->onceListeners[$eventName] : [] + $this->listeners[$eventName] ?? [], + $this->onceListeners[$eventName] ?? [] ); } return $events; } return array_merge( - isset($this->listeners[$event]) ? $this->listeners[$event] : [], - isset($this->onceListeners[$event]) ? $this->onceListeners[$event] : [] + $this->listeners[$event] ?? [], + $this->onceListeners[$event] ?? [] ); } - public function emit($event, array $arguments = []) + /** + * @param array $arguments + */ + public function emit(?string $event, array $arguments = []): void { if ($event === null) { throw new InvalidArgumentException('event name must not be null'); @@ -138,14 +155,15 @@ public function emit($event, array $arguments = []) $onceListeners = array_values($this->onceListeners[$event]); } - if(empty($listeners) === false) { + if ($listeners !== []) { foreach ($listeners as $listener) { $listener(...$arguments); } } - if(empty($onceListeners) === false) { + if ($onceListeners !== []) { unset($this->onceListeners[$event]); + foreach ($onceListeners as $listener) { $listener(...$arguments); } diff --git a/tests/EventEmitterTest.php b/tests/EventEmitterTest.php index bed43f8..a4cc0bb 100644 --- a/tests/EventEmitterTest.php +++ b/tests/EventEmitterTest.php @@ -13,60 +13,62 @@ use Evenement\EventEmitter; use InvalidArgumentException; +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; +#[CoversClass(EventEmitter::class)] +#[BackupGlobals(false)] +#[BackupStaticProperties(false)] class EventEmitterTest extends TestCase { /** * @var EventEmitter */ - private $emitter; + private EventEmitter $emitter; - /** - * @before - */ - public function setUpEmitter() + #[Before] + public function setUpEmitter(): void { $this->emitter = new EventEmitter(); } - public function testAddListenerWithLambda() + public function testAddListenerWithLambda(): void { - $this->emitter->on('foo', function () {}); + $this->emitter->on('foo', static function (): void {}); - $this->assertEquals(1, count($this->emitter->listeners('foo'))); + $this->assertCount(1, $this->emitter->listeners('foo')); } - public function testAddListenerWithMethod() + public function testAddListenerWithMethod(): void { $listener = new Listener(); $this->emitter->on('foo', [$listener, 'onFoo']); - $this->assertEquals(1, count($this->emitter->listeners('foo'))); + $this->assertCount(1, $this->emitter->listeners('foo')); } - public function testAddListenerWithStaticMethod() + public function testAddListenerWithStaticMethod(): void { $this->emitter->on('bar', ['Evenement\Tests\Listener', 'onBar']); - $this->assertEquals(1, count($this->emitter->listeners('bar'))); + $this->assertCount(1, $this->emitter->listeners('bar')); } - public function testAddListenerWithInvalidListener() + public function testAddListenerWithInvalidListener(): void { - try { - $this->emitter->on('foo', 'not a callable'); - $this->fail(); - } catch (\Exception $e) { - } catch (\TypeError $e) { - } + $this->expectException(\TypeError::class); + $this->emitter->on('foo', 'not a callable'); } - public function testOnce() + public function testOnce(): void { $listenerCalled = 0; - $this->emitter->once('foo', function () use (&$listenerCalled) { + $this->emitter->once('foo', static function () use (&$listenerCalled): void { $listenerCalled++; }); @@ -81,24 +83,24 @@ public function testOnce() $this->assertSame(1, $listenerCalled); } - public function testOnceWithArguments() + public function testOnceWithArguments(): void { $capturedArgs = []; - $this->emitter->once('foo', function ($a, $b) use (&$capturedArgs) { - $capturedArgs = array($a, $b); + $this->emitter->once('foo', static function (string $a, string $b) use (&$capturedArgs): void { + $capturedArgs = [$a, $b]; }); - $this->emitter->emit('foo', array('a', 'b')); + $this->emitter->emit('foo', ['a', 'b']); - $this->assertSame(array('a', 'b'), $capturedArgs); + $this->assertSame(['a', 'b'], $capturedArgs); } - public function testEmitWithoutArguments() + public function testEmitWithoutArguments(): void { $listenerCalled = false; - $this->emitter->on('foo', function () use (&$listenerCalled) { + $this->emitter->on('foo', static function () use (&$listenerCalled): void { $listenerCalled = true; }); @@ -107,13 +109,13 @@ public function testEmitWithoutArguments() $this->assertSame(true, $listenerCalled); } - public function testEmitWithOneArgument() + public function testEmitWithOneArgument(): void { $test = $this; $listenerCalled = false; - $this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) { + $this->emitter->on('foo', static function (string $value) use (&$listenerCalled, $test): void { $listenerCalled = true; $test->assertSame('bar', $value); @@ -124,13 +126,13 @@ public function testEmitWithOneArgument() $this->assertSame(true, $listenerCalled); } - public function testEmitWithTwoArguments() + public function testEmitWithTwoArguments(): void { $test = $this; $listenerCalled = false; - $this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) { + $this->emitter->on('foo', static function (string $arg1, string $arg2) use (&$listenerCalled, $test): void { $listenerCalled = true; $test->assertSame('bar', $arg1); @@ -142,22 +144,23 @@ public function testEmitWithTwoArguments() $this->assertSame(true, $listenerCalled); } - public function testEmitWithNoListeners() + #[DoesNotPerformAssertions] + public function testEmitWithNoListeners(): void { $this->emitter->emit('foo'); $this->emitter->emit('foo', ['bar']); $this->emitter->emit('foo', ['bar', 'baz']); } - public function testEmitWithTwoListeners() + public function testEmitWithTwoListeners(): void { $listenersCalled = 0; - $this->emitter->on('foo', function () use (&$listenersCalled) { + $this->emitter->on('foo', static function () use (&$listenersCalled): void { $listenersCalled++; }); - $this->emitter->on('foo', function () use (&$listenersCalled) { + $this->emitter->on('foo', static function () use (&$listenersCalled): void { $listenersCalled++; }); @@ -166,11 +169,11 @@ public function testEmitWithTwoListeners() $this->assertSame(2, $listenersCalled); } - public function testRemoveListenerMatching() + public function testRemoveListenerMatching(): void { $listenersCalled = 0; - $listener = function () use (&$listenersCalled) { + $listener = static function () use (&$listenersCalled): void { $listenersCalled++; }; @@ -182,11 +185,11 @@ public function testRemoveListenerMatching() $this->assertSame(0, $listenersCalled); } - public function testRemoveListenerNotMatching() + public function testRemoveListenerNotMatching(): void { $listenersCalled = 0; - $listener = function () use (&$listenersCalled) { + $listener = static function () use (&$listenersCalled): void { $listenersCalled++; }; @@ -198,11 +201,11 @@ public function testRemoveListenerNotMatching() $this->assertSame(1, $listenersCalled); } - public function testRemoveAllListenersMatching() + public function testRemoveAllListenersMatching(): void { $listenersCalled = 0; - $this->emitter->on('foo', function () use (&$listenersCalled) { + $this->emitter->on('foo', static function () use (&$listenersCalled): void { $listenersCalled++; }); @@ -213,11 +216,11 @@ public function testRemoveAllListenersMatching() $this->assertSame(0, $listenersCalled); } - public function testRemoveAllListenersNotMatching() + public function testRemoveAllListenersNotMatching(): void { $listenersCalled = 0; - $this->emitter->on('foo', function () use (&$listenersCalled) { + $this->emitter->on('foo', static function () use (&$listenersCalled): void { $listenersCalled++; }); @@ -228,15 +231,15 @@ public function testRemoveAllListenersNotMatching() $this->assertSame(1, $listenersCalled); } - public function testRemoveAllListenersWithoutArguments() + public function testRemoveAllListenersWithoutArguments(): void { $listenersCalled = 0; - $this->emitter->on('foo', function () use (&$listenersCalled) { + $this->emitter->on('foo', static function () use (&$listenersCalled): void { $listenersCalled++; }); - $this->emitter->on('bar', function () use (&$listenersCalled) { + $this->emitter->on('bar', static function () use (&$listenersCalled): void { $listenersCalled++; }); @@ -248,11 +251,11 @@ public function testRemoveAllListenersWithoutArguments() $this->assertSame(0, $listenersCalled); } - public function testCallablesClosure() + public function testCallablesClosure(): void { $calledWith = null; - $this->emitter->on('foo', function ($data) use (&$calledWith) { + $this->emitter->on('foo', static function (?string $data) use (&$calledWith): void { $calledWith = $data; }); @@ -261,7 +264,7 @@ public function testCallablesClosure() self::assertSame('bar', $calledWith); } - public function testCallablesClass() + public function testCallablesClass(): void { $listener = new Listener(); $this->emitter->on('foo', [$listener, 'onFoo']); @@ -272,7 +275,7 @@ public function testCallablesClass() } - public function testCallablesClassInvoke() + public function testCallablesClassInvoke(): void { $listener = new Listener(); $this->emitter->on('foo', $listener); @@ -282,7 +285,7 @@ public function testCallablesClassInvoke() self::assertSame(['bar'], $listener->getMagicData()); } - public function testCallablesStaticClass() + public function testCallablesStaticClass(): void { $this->emitter->on('foo', '\Evenement\Tests\Listener::onBar'); @@ -291,7 +294,7 @@ public function testCallablesStaticClass() self::assertSame(['bar'], Listener::getStaticData()); } - public function testCallablesFunction() + public function testCallablesFunction(): void { $this->emitter->on('foo', '\Evenement\Tests\setGlobalTestData'); @@ -302,14 +305,14 @@ public function testCallablesFunction() unset($GLOBALS['evenement-evenement-test-data']); } - public function testListeners() + public function testListeners(): void { - $onA = function () {}; - $onB = function () {}; - $onC = function () {}; - $onceA = function () {}; - $onceB = function () {}; - $onceC = function () {}; + $onA = static function (): void {}; + $onB = static function (): void {}; + $onC = static function (): void {}; + $onceA = static function (): void {}; + $onceB = static function (): void {}; + $onceC = static function (): void {}; self::assertCount(0, $this->emitter->listeners('event')); $this->emitter->on('event', $onA); @@ -342,16 +345,21 @@ public function testListeners() $this->emitter->emit('event'); self::assertCount(2, $this->emitter->listeners('event')); self::assertSame([$onA, $onC], $this->emitter->listeners('event')); + $this->emitter->removeAllListeners(); + $this->emitter->once('event', $onceA); + self::assertCount(1, $this->emitter->listeners('event')); + $this->emitter->removeListener('event', $onceA); + self::assertCount(0, $this->emitter->listeners('event')); } - public function testOnceCallIsNotRemovedWhenWorkingOverOnceListeners() + public function testOnceCallIsNotRemovedWhenWorkingOverOnceListeners(): void { $aCalled = false; - $aCallable = function () use (&$aCalled) { + $aCallable = static function () use (&$aCalled): void { $aCalled = true; }; $bCalled = false; - $bCallable = function () use (&$bCalled, $aCallable) { + $bCallable = function () use (&$bCalled, $aCallable): void { $bCalled = true; $this->emitter->once('event', $aCallable); }; @@ -369,32 +377,31 @@ public function testOnceCallIsNotRemovedWhenWorkingOverOnceListeners() self::assertTrue($bCalled); } - public function testEventNameMustBeStringOn() + public function testEventNameMustBeStringOn(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('event name must not be null'); - $this->emitter->on(null, function () { - }); + $this->emitter->on(null, static function (): void {}); } - public function testEventNameMustBeStringOnce() + public function testEventNameMustBeStringOnce(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('event name must not be null'); - $this->emitter->once(null, function () {}); + $this->emitter->once(null, static function (): void {}); } - public function testEventNameMustBeStringRemoveListener() + public function testEventNameMustBeStringRemoveListener(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('event name must not be null'); - $this->emitter->removeListener(null, function () {}); + $this->emitter->removeListener(null, static function (): void {}); } - public function testEventNameMustBeStringEmit() + public function testEventNameMustBeStringEmit(): void { self::expectException(InvalidArgumentException::class); self::expectExceptionMessage('event name must not be null'); @@ -402,12 +409,12 @@ public function testEventNameMustBeStringEmit() $this->emitter->emit(null); } - public function testListenersGetAll() + public function testListenersGetAll(): void { - $a = function () {}; - $b = function () {}; - $c = function () {}; - $d = function () {}; + $a = static function (): void {}; + $b = static function (): void {}; + $c = static function (): void {}; + $d = static function (): void {}; $this->emitter->once('event2', $c); $this->emitter->on('event', $a); @@ -431,14 +438,14 @@ public function testListenersGetAll() ); } - public function testOnceNestedCallRegression() + public function testOnceNestedCallRegression(): void { $first = 0; $second = 0; - $this->emitter->once('event', function () use (&$first, &$second) { + $this->emitter->once('event', function () use (&$first, &$second): void { $first++; - $this->emitter->once('event', function () use (&$second) { + $this->emitter->once('event', static function () use (&$second): void { $second++; }); $this->emitter->emit('event'); @@ -449,7 +456,7 @@ public function testOnceNestedCallRegression() self::assertSame(1, $second); } - public function testNestedOn() + public function testNestedOn(): void { $emitter = $this->emitter; @@ -457,13 +464,13 @@ public function testNestedOn() $second = 0; $third = 0; - $emitter->on('event', function () use (&$emitter, &$first, &$second, &$third) { + $emitter->on('event', static function () use (&$emitter, &$first, &$second, &$third): void { $first++; - $emitter->on('event', function () use (&$second, &$third) { + $emitter->on('event', static function () use (&$second, &$third): void { $second++; }) - ->once('event', function () use (&$third) { + ->once('event', static function () use (&$third): void { $third++; }); }); From 3b51d5b3e54753ad6d8ded6f8cfb8bdd8bae511d Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:16:35 -0400 Subject: [PATCH 02/11] Update .gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index b2b76c3..18c0f1a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,6 +5,7 @@ /doc export-ignore /examples export-ignore /tests export-ignore +/.gitattributes export-ignore /.gitignore export-ignore /CHANGELOG.md export-ignore /phpunit.xml.dist export-ignore From 3eee42fb085a36fdfe538849fe203780e1dc4bd3 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:19:52 -0400 Subject: [PATCH 03/11] PHP 8.1 --- composer.json | 2 +- phpunit.xml.dist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index da6ffa0..d54fa84 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": ">=8.0" + "php": ">=8.1" }, "require-dev": { "phpunit/phpunit": "^10 || ^11" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a7ac001..ee9cece 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,7 +20,7 @@ - + ./src/ From 8e64af8be16d7dcc595136bdb6b25bbdd0b2d3c3 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:37:51 -0400 Subject: [PATCH 04/11] Update examples/benchmarks --- examples/benchmark-emit-no-arguments.php | 2 +- examples/benchmark-emit-once.php | 2 +- examples/benchmark-emit-one-argument.php | 2 +- examples/benchmark-emit.php | 2 +- examples/benchmark-remove-listener-once.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/benchmark-emit-no-arguments.php b/examples/benchmark-emit-no-arguments.php index 53d7f4b..ac94224 100644 --- a/examples/benchmark-emit-no-arguments.php +++ b/examples/benchmark-emit-no-arguments.php @@ -17,7 +17,7 @@ $emitter = new EventEmitter(); -$emitter->on('event', function () {}); +$emitter->on('event', static function (): void {}); $start = microtime(true); for ($i = 0; $i < ITERATIONS; $i++) { diff --git a/examples/benchmark-emit-once.php b/examples/benchmark-emit-once.php index 74f4d17..e08c6f1 100644 --- a/examples/benchmark-emit-once.php +++ b/examples/benchmark-emit-once.php @@ -20,7 +20,7 @@ $emitter = new EventEmitter(); for ($i = 0; $i < ITERATIONS; $i++) { - $emitter->once('event', function ($a, $b, $c) {}); + $emitter->once('event', static function (int $a, int $b, int $c): void {}); } $start = microtime(true); diff --git a/examples/benchmark-emit-one-argument.php b/examples/benchmark-emit-one-argument.php index 39fc4ba..586ce56 100644 --- a/examples/benchmark-emit-one-argument.php +++ b/examples/benchmark-emit-one-argument.php @@ -17,7 +17,7 @@ $emitter = new EventEmitter(); -$emitter->on('event', function ($a) {}); +$emitter->on('event', static function (int $a): void {}); $start = microtime(true); for ($i = 0; $i < ITERATIONS; $i++) { diff --git a/examples/benchmark-emit.php b/examples/benchmark-emit.php index 3ab639e..0d37fb3 100644 --- a/examples/benchmark-emit.php +++ b/examples/benchmark-emit.php @@ -17,7 +17,7 @@ $emitter = new EventEmitter(); -$emitter->on('event', function ($a, $b, $c) {}); +$emitter->on('event', static function (int $a, int $b, int $c): void {}); $start = microtime(true); for ($i = 0; $i < ITERATIONS; $i++) { diff --git a/examples/benchmark-remove-listener-once.php b/examples/benchmark-remove-listener-once.php index 414be3b..445072a 100644 --- a/examples/benchmark-remove-listener-once.php +++ b/examples/benchmark-remove-listener-once.php @@ -21,7 +21,7 @@ $listeners = []; for ($i = 0; $i < ITERATIONS; $i++) { - $listeners[] = function ($a, $b, $c) {}; + $listeners[] = static function (int $a, int $b, int $c): void {}; } $start = microtime(true); From 988c5fdc1bccbbf7d26b186a9e9abc1eebde2914 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:53:34 -0400 Subject: [PATCH 05/11] fix argument type, null should throw typeerror, instead check for empty string --- src/EventEmitterInterface.php | 8 ++++---- src/EventEmitterTrait.php | 24 ++++++++++++------------ tests/EventEmitterTest.php | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/EventEmitterInterface.php b/src/EventEmitterInterface.php index 00444be..1415eb6 100644 --- a/src/EventEmitterInterface.php +++ b/src/EventEmitterInterface.php @@ -16,18 +16,18 @@ interface EventEmitterInterface /** * Allows you to subscribe to an event. */ - public function on(?string $event, callable $listener): static; + public function on(string $event, callable $listener): static; /** * Convenience method that adds a listener which is guaranteed to only be * called once. */ - public function once(?string $event, callable $listener): static; + public function once(string $event, callable $listener): static; /** * Remove a specific listener for a specific event. */ - public function removeListener(?string $event, callable $listener): void; + public function removeListener(string $event, callable $listener): void; /** * Remove all listeners for a specific event or all listeners all together. @@ -46,5 +46,5 @@ public function listeners(?string $event = null): array; /** * Emit an event, which will call all listeners. */ - public function emit(?string $event, array $arguments = []): void; + public function emit(string $event, array $arguments = []): void; } diff --git a/src/EventEmitterTrait.php b/src/EventEmitterTrait.php index e65d68e..c86b292 100644 --- a/src/EventEmitterTrait.php +++ b/src/EventEmitterTrait.php @@ -31,10 +31,10 @@ trait EventEmitterTrait */ protected array $onceListeners = []; - public function on(?string $event, callable $listener): static + public function on(string $event, callable $listener): static { - if ($event === null) { - throw new InvalidArgumentException('event name must not be null'); + if ($event === '') { + throw new InvalidArgumentException('event name must not be an empty string'); } if (!isset($this->listeners[$event])) { @@ -46,10 +46,10 @@ public function on(?string $event, callable $listener): static return $this; } - public function once(?string $event, callable $listener): static + public function once(string $event, callable $listener): static { - if ($event === null) { - throw new InvalidArgumentException('event name must not be null'); + if ($event === '') { + throw new InvalidArgumentException('event name must not be an empty string'); } if (!isset($this->onceListeners[$event])) { @@ -61,10 +61,10 @@ public function once(?string $event, callable $listener): static return $this; } - public function removeListener(?string $event, callable $listener): void + public function removeListener(string $event, callable $listener): void { - if ($event === null) { - throw new InvalidArgumentException('event name must not be null'); + if ($event === '') { + throw new InvalidArgumentException('event name must not be an empty string'); } if (isset($this->listeners[$event])) { @@ -139,10 +139,10 @@ public function listeners(?string $event = null): array /** * @param array $arguments */ - public function emit(?string $event, array $arguments = []): void + public function emit(string $event, array $arguments = []): void { - if ($event === null) { - throw new InvalidArgumentException('event name must not be null'); + if ($event === '') { + throw new InvalidArgumentException('event name must not be an empty string'); } $listeners = []; diff --git a/tests/EventEmitterTest.php b/tests/EventEmitterTest.php index a4cc0bb..8924d38 100644 --- a/tests/EventEmitterTest.php +++ b/tests/EventEmitterTest.php @@ -380,33 +380,33 @@ public function testOnceCallIsNotRemovedWhenWorkingOverOnceListeners(): void public function testEventNameMustBeStringOn(): void { self::expectException(InvalidArgumentException::class); - self::expectExceptionMessage('event name must not be null'); + self::expectExceptionMessage('event name must not be an empty string'); - $this->emitter->on(null, static function (): void {}); + $this->emitter->on('', static function (): void {}); } public function testEventNameMustBeStringOnce(): void { self::expectException(InvalidArgumentException::class); - self::expectExceptionMessage('event name must not be null'); + self::expectExceptionMessage('event name must not be an empty string'); - $this->emitter->once(null, static function (): void {}); + $this->emitter->once('', static function (): void {}); } public function testEventNameMustBeStringRemoveListener(): void { self::expectException(InvalidArgumentException::class); - self::expectExceptionMessage('event name must not be null'); + self::expectExceptionMessage('event name must not be an empty string'); - $this->emitter->removeListener(null, static function (): void {}); + $this->emitter->removeListener('', static function (): void {}); } public function testEventNameMustBeStringEmit(): void { self::expectException(InvalidArgumentException::class); - self::expectExceptionMessage('event name must not be null'); + self::expectExceptionMessage('event name must not be an empty string'); - $this->emitter->emit(null); + $this->emitter->emit(''); } public function testListenersGetAll(): void From 8744a34aa25311758d927d1d2ecf03a46c05d727 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 02:57:50 -0400 Subject: [PATCH 06/11] Update 01-api.md --- doc/01-api.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/01-api.md b/doc/01-api.md index 307487f..99ce0ba 100644 --- a/doc/01-api.md +++ b/doc/01-api.md @@ -6,7 +6,7 @@ define an interface that extends the emitter and implicitly defines certain events to be emitted, or if you want to type hint an `EventEmitter` to be passed to a method without coupling to the specific implementation. -## on(?string $event, callable $listener): static; +## on(string $event, callable $listener): static; Allows you to subscribe to an event. @@ -35,7 +35,7 @@ You can also accept more than one parameter for the listener: $emitter->on('numbers_added', static function (int $result, int $a, int $b): void {}); ``` -## once(?string $event, callable $listener): static; +## once(string $event, callable $listener): static; Convenience method that adds a listener which is guaranteed to only be called once. @@ -48,7 +48,7 @@ $conn->once('connected', static function () use ($conn, $data): void { }); ``` -## emit(?string $event, array $arguments = []): void; +## emit(string $event, array $arguments = []): void; Emit an event, which will call all listeners. @@ -66,7 +66,7 @@ $result = $a + $b; $emitter->emit('numbers_added', [$result, $a, $b]); ``` -## listeners(?string $event): array; +## listeners(?string $event = null): array; Allows you to inspect the listeners attached to an event. Particularly useful to check if there are any listeners at all. @@ -80,7 +80,7 @@ if (0 === \count($emitter->listeners('error'))) { } ``` -## removeListener(?string $event, callable $listener): void; +## removeListener(string $event, callable $listener): void; Remove a specific listener for a specific event. From 01bfb7bddfbeada847948e503035421db256fe72 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Wed, 17 Apr 2024 04:07:33 -0400 Subject: [PATCH 07/11] Update tests/Listener and functions --- tests/Listener.php | 36 +++++++++++++++++++++++++++--------- tests/functions.php | 2 +- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/tests/Listener.php b/tests/Listener.php index df17424..464afa0 100644 --- a/tests/Listener.php +++ b/tests/Listener.php @@ -13,38 +13,56 @@ class Listener { - private $data = []; + /** + * @var list + */ + private array $data = []; - private $magicData = []; + /** + * @var list + */ + private array $magicData = []; - private static $staticData = []; + /** + * @var list + */ + private static array $staticData = []; - public function onFoo($data) + public function onFoo(string $data): void { $this->data[] = $data; } - public function __invoke($data) + public function __invoke(string $data): void { $this->magicData[] = $data; } - public static function onBar($data) + public static function onBar(string $data): void { self::$staticData[] = $data; } - public function getData() + /** + * @return list + */ + public function getData(): array { return $this->data; } - public function getMagicData() + /** + * @return list + */ + public function getMagicData(): array { return $this->magicData; } - public static function getStaticData() + /** + * @return list + */ + public static function getStaticData(): array { return self::$staticData; } diff --git a/tests/functions.php b/tests/functions.php index 7f11f5b..39d03c0 100644 --- a/tests/functions.php +++ b/tests/functions.php @@ -11,7 +11,7 @@ namespace Evenement\Tests; -function setGlobalTestData($data) +function setGlobalTestData(string $data): void { $GLOBALS['evenement-evenement-test-data'] = $data; } From 27baece6af412b9eafb2ff35f25b4a8eb5067d69 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Mon, 29 Apr 2024 04:17:07 -0400 Subject: [PATCH 08/11] Update removeAllListeners A slight optimization of sorts. Instead of checking for $event being null for both listeners and onceListeners, make it a single check. --- src/EventEmitterTrait.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/EventEmitterTrait.php b/src/EventEmitterTrait.php index c86b292..d0f8294 100644 --- a/src/EventEmitterTrait.php +++ b/src/EventEmitterTrait.php @@ -95,14 +95,9 @@ public function removeListener(string $event, callable $listener): void public function removeAllListeners(?string $event = null): void { if ($event !== null) { - unset($this->listeners[$event]); + unset($this->listeners[$event], $this->onceListeners[$event]); } else { $this->listeners = []; - } - - if ($event !== null) { - unset($this->onceListeners[$event]); - } else { $this->onceListeners = []; } } From b737a67960d1e575c61dd8e998892e9850b32558 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Tue, 30 Apr 2024 05:45:33 -0400 Subject: [PATCH 09/11] Update ci.yaml Replaces deprecated 'set-output' and removes the composer-action-hash since composer isn't part of the matrix strategy. --- .github/workflows/ci.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9d6d848..661824f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,18 +38,15 @@ jobs: - name: Get composer cache directory id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Get composer action hash - id: composer-action-hash - run: printf "::set-output name=hash::%s" $(echo -n "${{ matrix.composer }}" | sha512sum) + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Cache dependencies uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer-${{ steps.composer-action-hash.outputs.hash }} + restore-keys: ${{ runner.os }}-composer- - name: Install Composer dependencies run: composer install --no-progress --no-interaction --no-suggest --optimize-autoloader --ansi From 99d2b7b60a8fd09194131d50b29bb90ce6758682 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Tue, 30 Apr 2024 06:06:22 -0400 Subject: [PATCH 10/11] Update ci.yaml --- .github/workflows/ci.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 661824f..8017dc2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,11 +45,14 @@ jobs: uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- + key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.json') }} + restore-keys: | + composer-${{ runner.os }}-${{ matrix.php }} + composer-${{ runner.os }}- + composer- - name: Install Composer dependencies - run: composer install --no-progress --no-interaction --no-suggest --optimize-autoloader --ansi + run: composer install --no-progress --no-interaction --optimize-autoloader --ansi - name: Test run: | From 4bd2aeb18c2a7aebf96a3befe247301a3a5f58b7 Mon Sep 17 00:00:00 2001 From: Eric Sizemore Date: Mon, 20 May 2024 19:23:40 -0400 Subject: [PATCH 11/11] changes to bring inline with pr review https://github.com/igorw/evenement/pull/88 - add ramsey/composer-install - fix docblocks - add import for count function - updated unit test preferring 'self':: over 'this->' for assertSame/assertCount --- .github/workflows/ci.yaml | 22 ++-------- .gitignore | 2 +- src/EventEmitterInterface.php | 4 ++ src/EventEmitterTrait.php | 12 ++---- tests/EventEmitterTest.php | 81 ++++++++++++++++------------------- 5 files changed, 49 insertions(+), 72 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8017dc2..54f2850 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,31 +28,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup PHP, extensions and composer with shivammathur/setup-php + - name: Setup PHP and extensions with shivammathur/setup-php uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: mbstring, ctype, iconv, bcmath, filter, json coverage: xdebug, pcov - tools: composer:v2 - - name: Get composer cache directory - id: composer-cache - run: | - echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Cache dependencies - uses: actions/cache@v4 + - name: Setup Composer, install dependencies + uses: ramsey/composer-install@v3 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.json') }} - restore-keys: | - composer-${{ runner.os }}-${{ matrix.php }} - composer-${{ runner.os }}- - composer- - - - name: Install Composer dependencies - run: composer install --no-progress --no-interaction --optimize-autoloader --ansi + composer-options: "--optimize-autoloader" - name: Test run: | diff --git a/.gitignore b/.gitignore index 48a56c0..7330583 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ composer.lock vendor .phpunit.result.cache -.phpunit.cache \ No newline at end of file +.phpunit.cache diff --git a/src/EventEmitterInterface.php b/src/EventEmitterInterface.php index 1415eb6..8dfc878 100644 --- a/src/EventEmitterInterface.php +++ b/src/EventEmitterInterface.php @@ -40,11 +40,15 @@ public function removeAllListeners(?string $event = null): void; /** * Allows you to inspect the listeners attached to an event. Particularly useful * to check if there are any listeners at all. + * + * @return array>|list<(callable)> */ public function listeners(?string $event = null): array; /** * Emit an event, which will call all listeners. + * + * @param array $arguments */ public function emit(string $event, array $arguments = []): void; } diff --git a/src/EventEmitterTrait.php b/src/EventEmitterTrait.php index d0f8294..795c1c5 100644 --- a/src/EventEmitterTrait.php +++ b/src/EventEmitterTrait.php @@ -18,6 +18,7 @@ use function array_search; use function array_unique; use function array_values; +use function count; trait EventEmitterTrait { @@ -73,7 +74,7 @@ public function removeListener(string $event, callable $listener): void if (false !== $index) { unset($this->listeners[$event][$index]); - if (\count($this->listeners[$event]) === 0) { + if (count($this->listeners[$event]) === 0) { unset($this->listeners[$event]); } } @@ -85,7 +86,7 @@ public function removeListener(string $event, callable $listener): void if (false !== $index) { unset($this->onceListeners[$event][$index]); - if (\count($this->onceListeners[$event]) === 0) { + if (count($this->onceListeners[$event]) === 0) { unset($this->onceListeners[$event]); } } @@ -102,9 +103,6 @@ public function removeAllListeners(?string $event = null): void } } - /** - * @return array>|list<(callable)> - */ public function listeners(?string $event = null): array { if ($event === null) { @@ -122,6 +120,7 @@ public function listeners(?string $event = null): array $this->onceListeners[$eventName] ?? [] ); } + return $events; } @@ -131,9 +130,6 @@ public function listeners(?string $event = null): array ); } - /** - * @param array $arguments - */ public function emit(string $event, array $arguments = []): void { if ($event === '') { diff --git a/tests/EventEmitterTest.php b/tests/EventEmitterTest.php index 8924d38..ad9dbed 100644 --- a/tests/EventEmitterTest.php +++ b/tests/EventEmitterTest.php @@ -21,13 +21,8 @@ use PHPUnit\Framework\TestCase; #[CoversClass(EventEmitter::class)] -#[BackupGlobals(false)] -#[BackupStaticProperties(false)] class EventEmitterTest extends TestCase { - /** - * @var EventEmitter - */ private EventEmitter $emitter; #[Before] @@ -40,7 +35,7 @@ public function testAddListenerWithLambda(): void { $this->emitter->on('foo', static function (): void {}); - $this->assertCount(1, $this->emitter->listeners('foo')); + self::assertCount(1, $this->emitter->listeners('foo')); } public function testAddListenerWithMethod(): void @@ -48,14 +43,14 @@ public function testAddListenerWithMethod(): void $listener = new Listener(); $this->emitter->on('foo', [$listener, 'onFoo']); - $this->assertCount(1, $this->emitter->listeners('foo')); + self::assertCount(1, $this->emitter->listeners('foo')); } public function testAddListenerWithStaticMethod(): void { $this->emitter->on('bar', ['Evenement\Tests\Listener', 'onBar']); - $this->assertCount(1, $this->emitter->listeners('bar')); + self::assertCount(1, $this->emitter->listeners('bar')); } public function testAddListenerWithInvalidListener(): void @@ -72,15 +67,15 @@ public function testOnce(): void $listenerCalled++; }); - $this->assertSame(0, $listenerCalled); + self::assertSame(0, $listenerCalled); $this->emitter->emit('foo'); - $this->assertSame(1, $listenerCalled); + self::assertSame(1, $listenerCalled); $this->emitter->emit('foo'); - $this->assertSame(1, $listenerCalled); + self::assertSame(1, $listenerCalled); } public function testOnceWithArguments(): void @@ -93,7 +88,7 @@ public function testOnceWithArguments(): void $this->emitter->emit('foo', ['a', 'b']); - $this->assertSame(['a', 'b'], $capturedArgs); + self::assertSame(['a', 'b'], $capturedArgs); } public function testEmitWithoutArguments(): void @@ -104,44 +99,40 @@ public function testEmitWithoutArguments(): void $listenerCalled = true; }); - $this->assertSame(false, $listenerCalled); + self::assertFalse($listenerCalled); $this->emitter->emit('foo'); - $this->assertSame(true, $listenerCalled); + self::assertTrue($listenerCalled); } public function testEmitWithOneArgument(): void { - $test = $this; - $listenerCalled = false; - $this->emitter->on('foo', static function (string $value) use (&$listenerCalled, $test): void { + $this->emitter->on('foo', static function (string $value) use (&$listenerCalled): void { $listenerCalled = true; - $test->assertSame('bar', $value); + self::assertSame('bar', $value); }); - $this->assertSame(false, $listenerCalled); + self::assertFalse($listenerCalled); $this->emitter->emit('foo', ['bar']); - $this->assertSame(true, $listenerCalled); + self::assertTrue($listenerCalled); } public function testEmitWithTwoArguments(): void { - $test = $this; - $listenerCalled = false; - $this->emitter->on('foo', static function (string $arg1, string $arg2) use (&$listenerCalled, $test): void { + $this->emitter->on('foo', static function (string $arg1, string $arg2) use (&$listenerCalled): void { $listenerCalled = true; - $test->assertSame('bar', $arg1); - $test->assertSame('baz', $arg2); + self::assertSame('bar', $arg1); + self::assertSame('baz', $arg2); }); - $this->assertSame(false, $listenerCalled); + self::assertFalse($listenerCalled); $this->emitter->emit('foo', ['bar', 'baz']); - $this->assertSame(true, $listenerCalled); + self::assertTrue($listenerCalled); } #[DoesNotPerformAssertions] @@ -164,9 +155,9 @@ public function testEmitWithTwoListeners(): void $listenersCalled++; }); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); - $this->assertSame(2, $listenersCalled); + self::assertSame(2, $listenersCalled); } public function testRemoveListenerMatching(): void @@ -180,9 +171,9 @@ public function testRemoveListenerMatching(): void $this->emitter->on('foo', $listener); $this->emitter->removeListener('foo', $listener); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); } public function testRemoveListenerNotMatching(): void @@ -196,9 +187,9 @@ public function testRemoveListenerNotMatching(): void $this->emitter->on('foo', $listener); $this->emitter->removeListener('bar', $listener); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); - $this->assertSame(1, $listenersCalled); + self::assertSame(1, $listenersCalled); } public function testRemoveAllListenersMatching(): void @@ -211,9 +202,9 @@ public function testRemoveAllListenersMatching(): void $this->emitter->removeAllListeners('foo'); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); } public function testRemoveAllListenersNotMatching(): void @@ -226,9 +217,9 @@ public function testRemoveAllListenersNotMatching(): void $this->emitter->removeAllListeners('bar'); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); - $this->assertSame(1, $listenersCalled); + self::assertSame(1, $listenersCalled); } public function testRemoveAllListenersWithoutArguments(): void @@ -245,10 +236,10 @@ public function testRemoveAllListenersWithoutArguments(): void $this->emitter->removeAllListeners(); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); $this->emitter->emit('foo'); $this->emitter->emit('bar'); - $this->assertSame(0, $listenersCalled); + self::assertSame(0, $listenersCalled); } public function testCallablesClosure(): void @@ -476,12 +467,12 @@ public function testNestedOn(): void }); $emitter->emit('event'); - $this->assertEquals(1, $first); - $this->assertEquals(0, $second); - $this->assertEquals(0, $third); + self::assertSame(1, $first); + self::assertSame(0, $second); + self::assertSame(0, $third); $emitter->emit('event'); - $this->assertEquals(2, $first); - $this->assertEquals(1, $second); - $this->assertEquals(1, $third); + self::assertSame(2, $first); + self::assertSame(1, $second); + self::assertSame(1, $third); } }