Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase PHP requirement to 8.1 #88

Merged
merged 11 commits into from
Jul 8, 2024

Conversation

ericsizemore
Copy link
Contributor

The goal of this PR is to update Evenement to increase the requirement to PHP 8 (specifically 8.1); in reference to #87
This is my initial pass through. All tests are passing on my fork/branch, though obviously it will fail here for PHP 7.0 - 8.0.
Also, of course this would require a major version bump (4.0.0), though I did not edit the CHANGELOG.

Why PHP 8.1

Notable Changes

  • Require PHP >= 8.1
  • Add return / argument / property types throughout
  • Since arguments are now typed, with '$event' typed to 'string', the block which throws InvalidArgumentException now checks for empty string instead of null.
    • Exception message changed from event name must not be null to event name must not be an empty string
  • Replace use of the empty construct with a more strict comparison. E.g. if ($listeners !== []) {
  • Updated unit tests for PHPUnit >= 10.0
    • Updates EventEmitterTest and phpunit.xml.dist
    • Improved line code coverage to 100%
  • Updated GitHub CI workflow
    • actions/checkout v4
    • shivammathur/setup-php, tools:composer v2
    • actions/cache v4
  • Update function imports for compiler optimized functions.
  • Small updates/improvements to README and docs/01-api.md, 02-plugin-system.md

@ericsizemore
Copy link
Contributor Author

@igorw @WyriHaximus any thoughts, perhaps?

@WyriHaximus
Copy link
Collaborator

@igorw @WyriHaximus any thoughts, perhaps?

@ericsizemore First glace looks awesome, but will have a thorough look once I get back from a work trip next Sunday

@ericsizemore
Copy link
Contributor Author

@igorw @WyriHaximus any thoughts, perhaps?

@ericsizemore First glace looks awesome, but will have a thorough look once I get back from a work trip next Sunday

Sounds good. :)

--Side note, just noticed 'Unverified' next to my commits and briefly forgot that I just got my signing keys setup on GitHub and set vigilant mode 😆 Concerned me for a moment.

A slight optimization of sorts. Instead of checking for $event being null for both listeners and onceListeners, make it a single check.
Replaces deprecated 'set-output' and removes the composer-action-hash since composer isn't part of the matrix strategy.
@ericsizemore
Copy link
Contributor Author

ericsizemore commented Apr 30, 2024

One thing I noticed with the ci.yaml work flow is the use of set-output which is deprecated. Commit b737a67 replaced that usage. I also noticed a Get composer action hash step that didn't appear to work properly (there's no composer in the matrix strategy).

Since composer.lock is not committed to the repo, no hash is generated for the cache key. Instead, my latest commit changes that to the composer.json file with some additional restore keys. It also drops --no-suggest as it isn't needed for Composer v2. It has no effect and will break in Composer v3.

@ericsizemore
Copy link
Contributor Author

Howdy @WyriHaximus,

Just dropping in again, as it's been a few weeks. :)

@WyriHaximus WyriHaximus self-requested a review May 18, 2024 21:22
@WyriHaximus
Copy link
Collaborator

Sorry for the delay, having a look tomrrow

@ericsizemore
Copy link
Contributor Author

Sorry for the delay, having a look tomrrow

No worries at all! :)

@WyriHaximus WyriHaximus added this to the v4.0.0 milestone May 19, 2024
Copy link
Collaborator

@WyriHaximus WyriHaximus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loving all the things you've updated and put work into. A couple of things:

  • Added 13 comments for awesome things, requested changes, and some thoughts
  • Since this package is the basis for @reactphp we want to make sure it stays super performant, so I'm pinging @clue and @SimonFrings for their thoughts on this PR as well
  • Did you by any chance run the benchmark scripts to measure the percentual different in performance?
  • Great work, thank you for putting the time in improve it like this <3

.github/workflows/ci.yaml Outdated Show resolved Hide resolved
CHANGELOG.md Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
examples/benchmark-emit-no-arguments.php Show resolved Hide resolved
src/EventEmitterInterface.php Show resolved Hide resolved
src/EventEmitterTrait.php Outdated Show resolved Hide resolved
src/EventEmitterTrait.php Show resolved Hide resolved
tests/EventEmitterTest.php Show resolved Hide resolved
tests/EventEmitterTest.php Outdated Show resolved Hide resolved
tests/EventEmitterTest.php Outdated Show resolved Hide resolved
@ericsizemore
Copy link
Contributor Author

@WyriHaximus Thanks for the review! :) I am currently out of town so I will take a look at this when I get home tomorrow.

@ericsizemore
Copy link
Contributor Author

ericsizemore commented May 20, 2024

Loving all the things you've updated and put work into. A couple of things:

  • Added 13 comments for awesome things, requested changes, and some thoughts
  • Since this package is the basis for @reactphp we want to make sure it stays super performant, so I'm pinging @clue and @SimonFrings for their thoughts on this PR as well
  • Did you by any chance run the benchmark scripts to measure the percentual different in performance?
  • Great work, thank you for putting the time in improve it like this <3

I plan to look at the requested changes and reply/work towards a new commit later today. As for benchmarks, I have some data I can share. Note: I'm on Windows 11, using PHP 8.3.7 w/Xdebug; I unfortunately do not have a linux system to do these benchmarks on. I have data from the included files in examples/ and also from using phpbench.


PHPBench Results

I'm using the phpbench.phar version 1.2.15 with the following phpbench.json:

{
    "$schema":"https://raw.githubusercontent.com/phpbench/phpbench/master/phpbench.schema.json",
    "runner.bootstrap": "vendor/autoload.php"
}

and tests/Benchmark/EventEmitterBench.php

namespace Evenement\Tests\Benchmark;

use Evenement\EventEmitter;

class EventEmitterBench
{
    /**
     * @Revs(1000000)
     * @Iterations(3)
     */
    public function benchEmit()
    {
        $emitter = new EventEmitter();
        $emitter->on('event', static function (int $a, int $b, int $c): void {});
        $emitter->emit('event', [1, 2, 3]);
    }

    /**
     * @Revs(1000000)
     * @Iterations(3)
     */
    public function benchEmitOneArgument()
    {
        $emitter = new EventEmitter();
        $emitter->on('event', static function (int $a): void {});
        $emitter->emit('event', [1]);
    }

    /**
     * @Revs(1000000)
     * @Iterations(3)
     */
    public function benchEmitNoArguments()
    {
        $emitter = new EventEmitter();
        $emitter->on('event', static function (): void {});
        $emitter->emit('event');
    }

    /**
     * @Revs(100000)
     * @Iterations(3)
     */
    public function benchEmitOnce()
    {
        $emitter = new EventEmitter();
        $emitter->once('event', static function (int $a, int $b, int $c): void {});
        $emitter->emit('event', [1, 2, 3]);
    }

    /**
     * @Revs(3)
     * @Iterations(3)
     */
    public function benchRemoveListenerOnce()
    {
        $emitter = new EventEmitter();

        $listeners = [];
        for ($i = 0; $i < 100000; $i++) {
            $listeners[] = static function (int $a, int $b, int $c): void {};
        }

        foreach ($listeners as $listener) {
            $emitter->once('event', $listener);
        }

        foreach ($listeners as $listener) {
            $emitter->removeListener('event', $listener);
        }
    }
}

This pull request, php-8-support branch

$ php vendor/bin/phpbench.phar run tests/Benchmark/EventEmitterBench.php --report=aggregate
PHPBench (1.2.15) running benchmarks... #standwithukraine
with configuration file: phpbench.json
with PHP version 8.3.7, xdebug ✔, opcache ❌

\Evenement\Tests\Benchmark\EventEmitterBench

    benchEmit...............................I2 - Mo6.882μs (±0.22%)
    benchEmitOneArgument....................I2 - Mo6.751μs (±0.25%)
    benchEmitNoArguments....................I2 - Mo6.577μs (±0.35%)
    benchEmitOnce...........................I2 - Mo7.065μs (±2.74%)
    benchRemoveListenerOnce.................I2 - Mo4.301s (±2.58%)

Subjects: 5, Assertions: 0, Failures: 0, Errors: 0
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+
| benchmark         | subject                 | set | revs    | its | mem_peak | mode    | rstdev |
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+
| EventEmitterBench | benchEmit               |     | 1000000 | 3   | 1.966mb  | 6.882μs | ±0.22% |
| EventEmitterBench | benchEmitOneArgument    |     | 1000000 | 3   | 1.966mb  | 6.751μs | ±0.25% |
| EventEmitterBench | benchEmitNoArguments    |     | 1000000 | 3   | 1.966mb  | 6.577μs | ±0.35% |
| EventEmitterBench | benchEmitOnce           |     | 100000  | 3   | 1.966mb  | 7.065μs | ±2.74% |
| EventEmitterBench | benchRemoveListenerOnce |     | 3       | 3   | 49.272mb | 4.301s  | ±2.58% |
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+

Current master branch at igorw/evenement

$ php vendor/bin/phpbench.phar run tests/Benchmark/EventEmitterBench.php --report=aggregate
PHPBench (1.2.15) running benchmarks... #standwithukraine
with configuration file: phpbench.json
with PHP version 8.3.7, xdebug ✔, opcache ❌

\Evenement\Tests\Benchmark\EventEmitterBench

    benchEmit...............................I2 - Mo6.740μs (±0.27%)
    benchEmitOneArgument....................I2 - Mo6.726μs (±0.85%)
    benchEmitNoArguments....................I2 - Mo6.471μs (±0.87%)
    benchEmitOnce...........................I2 - Mo6.972μs (±1.12%)
    benchRemoveListenerOnce.................I2 - Mo4.282s (±0.45%)

Subjects: 5, Assertions: 0, Failures: 0, Errors: 0
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+
| benchmark         | subject                 | set | revs    | its | mem_peak | mode    | rstdev |
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+
| EventEmitterBench | benchEmit               |     | 1000000 | 3   | 1.723mb  | 6.740μs | ±0.27% |
| EventEmitterBench | benchEmitOneArgument    |     | 1000000 | 3   | 1.723mb  | 6.726μs | ±0.85% |
| EventEmitterBench | benchEmitNoArguments    |     | 1000000 | 3   | 1.723mb  | 6.471μs | ±0.87% |
| EventEmitterBench | benchEmitOnce           |     | 100000  | 3   | 1.723mb  | 6.972μs | ±1.12% |
| EventEmitterBench | benchRemoveListenerOnce |     | 3       | 3   | 49.025mb | 4.282s  | ±0.45% |
+-------------------+-------------------------+-----+---------+-----+----------+---------+--------+

Default examples/ scripts results

This pull request, php-8-support branch

$ find examples/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -n
Emitting one event to 100,000 once listeners took: 0.02s
Adding 100,000 once listeners took: 0.03s
Emitting 10,000,000 events took: 3.01s
Emitting 10,000,000 events took: 3.17s
Emitting 10,000,000 events took: 3.51s
Removing 100,000 once listeners took: 4.21s

Current master branch at igorw/evenement

$ find examples/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -n
Emitting one event to 100,000 once listeners took: 0.03s
Adding 100,000 once listeners took: 0.04s
Emitting 10,000,000 events took: 2.78s
Emitting 10,000,000 events took: 2.97s
Emitting 10,000,000 events took: 3.16s
Removing 100,000 once listeners took: 4.14s

igorw#88
- add ramsey/composer-install
- fix docblocks
- add import for count function
- updated unit test preferring 'self':: over 'this->' for assertSame/assertCount
@WyriHaximus
Copy link
Collaborator

WyriHaximus commented May 21, 2024

As for benchmarks, I have some data I can share. Note: I'm on Windows 11, using PHP 8.3.7 w/Xdebug; I unfortunately do not have a linux system to do these benchmarks on. I have data from the included files in examples/ and also from using phpbench.

Snipped benchmarks

No worries, thanks for running those. Looks like no percentile big changes. 🎉 OS doesn't matter, as long as there isn't an increase in runtime for the introduced changes.

@ericsizemore
Copy link
Contributor Author

As for benchmarks, I have some data I can share. Note: I'm on Windows 11, using PHP 8.3.7 w/Xdebug; I unfortunately do not have a linux system to do these benchmarks on. I have data from the included files in examples/ and also from using phpbench.
Snipped benchmarks

No worries, thanks for running those. Looks like no percentile big changes. 🎉 OS doesn't matter, as long as there isn't an increase in runtime for the introduced changes.

😄 Also, my apologies, I may have been a bit overzealous in marking some of the conversations as resolved, now that I look back on it. Though I believe 4bd2aeb covers everything with the exception of callable signatures.

@WyriHaximus
Copy link
Collaborator

As for benchmarks, I have some data I can share. Note: I'm on Windows 11, using PHP 8.3.7 w/Xdebug; I unfortunately do not have a linux system to do these benchmarks on. I have data from the included files in examples/ and also from using phpbench.
Snipped benchmarks

No worries, thanks for running those. Looks like no percentile big changes. 🎉 OS doesn't matter, as long as there isn't an increase in runtime for the introduced changes.

😄 Also, my apologies, I may have been a bit overzealous in marking some of the conversations as resolved, now that I look back on it. Though I believe 4bd2aeb covers everything with the exception of callable signatures.

No worries, I'll have a look at everything this weekend 👍

@ericsizemore
Copy link
Contributor Author

As for benchmarks, I have some data I can share. Note: I'm on Windows 11, using PHP 8.3.7 w/Xdebug; I unfortunately do not have a linux system to do these benchmarks on. I have data from the included files in examples/ and also from using phpbench.
Snipped benchmarks

No worries, thanks for running those. Looks like no percentile big changes. 🎉 OS doesn't matter, as long as there isn't an increase in runtime for the introduced changes.

😄 Also, my apologies, I may have been a bit overzealous in marking some of the conversations as resolved, now that I look back on it. Though I believe 4bd2aeb covers everything with the exception of callable signatures.

No worries, I'll have a look at everything this weekend 👍

Sounds good 👍

@WyriHaximus
Copy link
Collaborator

Sounds good 👍

Just FYI, I haven't forgotten about this, been having "fun" figuring out the callable template type 😅

@ericsizemore
Copy link
Contributor Author

Sounds good 👍

Just FYI, I haven't forgotten about this, been having "fun" figuring out the callable template type 😅

I feel that, haha. I wracked my brain on it a bit, but kept coming back to how I have it now. Since any callable can be passed, theoretically, it's hard to really get specific with the template type it seems.

@ericsizemore
Copy link
Contributor Author

Just popping in, to see where we are at. :)

@WyriHaximus
Copy link
Collaborator

Just popping in, to see where we are at. :)

Actively working on fixing the callable argument typing: reactphp-parallel/contracts#9

@ericsizemore
Copy link
Contributor Author

Just popping in, to see where we are at. :)

Actively working on fixing the callable argument typing: reactphp-parallel/contracts#9

I've been brainstorming this as well, and I see we've had similar ideas. I haven't quite nailed it yet, though.

@WyriHaximus
Copy link
Collaborator

Just popping in, to see where we are at. :)

Actively working on fixing the callable argument typing: reactphp-parallel/contracts#9

I've been brainstorming this as well, and I see we've had similar ideas. I haven't quite nailed it yet, though.

From what I've dug up today, there is no perfect solution. There is currently no way in PHPStan to make typing arguments work on intentionally infinite arguments for a function. (There is an open issue for it: phpstan/phpstan#8214.) I spent around 75% of the time working on that PR today just with the types tests. Those are worth it to add and get everything super clear.

@ericsizemore
Copy link
Contributor Author

Just popping in, to see where we are at. :)

Actively working on fixing the callable argument typing: reactphp-parallel/contracts#9

I've been brainstorming this as well, and I see we've had similar ideas. I haven't quite nailed it yet, though.

From what I've dug up today, there is no perfect solution. There is currently no way in PHPStan to make typing arguments work on intentionally infinite arguments for a function. (There is an open issue for it: phpstan/phpstan#8214.) I spent around 75% of the time working on that PR today just with the types tests. Those are worth it to add and get everything super clear.

Hmm. In this instance, perhaps we could move forward with (callable) as it is now, as that seems to satisfy PHPStan (for now). We could then revisit if/when phpstan/phpstan#8214 lands?

@WyriHaximus
Copy link
Collaborator

Just popping in, to see where we are at. :)

Actively working on fixing the callable argument typing: reactphp-parallel/contracts#9

I've been brainstorming this as well, and I see we've had similar ideas. I haven't quite nailed it yet, though.

From what I've dug up today, there is no perfect solution. There is currently no way in PHPStan to make typing arguments work on intentionally infinite arguments for a function. (There is an open issue for it: phpstan/phpstan#8214.) I spent around 75% of the time working on that PR today just with the types tests. Those are worth it to add and get everything super clear.

Hmm. In this instance, perhaps we could move forward with (callable) as it is now, as that seems to satisfy PHPStan (for now). We could then revisit if/when phpstan/phpstan#8214 lands?

I'll do a follow up after this PR to address this before releasing so it won't block this PR. I'll also reach out to Igor after I created the 4.x branch to make it the default so evenement/evenement:^4@dev can be used to install it file v4 is going finalized. Will review it again when I get home later today

WyriHaximus added a commit to WyriHaximus/php-test-utilities that referenced this pull request Jul 8, 2024
Copy link
Collaborator

@WyriHaximus WyriHaximus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great, thanks for the effort. I don't want to hold this one up any longer. For follow up PR's:

src/EventEmitterInterface.php Show resolved Hide resolved
@WyriHaximus WyriHaximus merged commit 0b04fab into igorw:master Jul 8, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants