Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

JBZoo Event is a lightweight PHP library for event-based development, providing an EventManager with support for event listeners, priorities, namespaces, and wildcard matching.

## Core Architecture

The library consists of three main components in the `src/` directory:

### EventManager (`src/EventManager.php`)
The core event manager class providing:
- Event subscription with priority levels (LOWEST=0, LOW=50, MID=100, HIGH=500, HIGHEST=1000)
- Namespace-based event matching with wildcards (e.g., `item.*`, `*.save`)
- One-time event listeners with `once()`
- Event propagation control via `ExceptionStop`
- Static default manager instance

### Exception Classes
- `Exception.php` - Base exception for the library
- `ExceptionStop.php` - Special exception to halt event propagation

## Common Commands

### Development Setup
```bash
make update # Install/update dependencies via Composer
```

### Testing
```bash
make test # Run PHPUnit tests
make test-all # Run all tests and code style checks
make codestyle # Run linters (PHPStan, Psalm, PHP-CS-Fixer, etc.)
```

### Individual QA Tools (via JBZoo Toolbox)
```bash
make test-phpstan # Static analysis
make test-psalm # Psalm analysis
make test-phpcs # Code style check
make test-phpcsfixer-fix # Auto-fix code style
make test-phpmd # Mess detector
```

### Reports
```bash
make report-all # Generate coverage and analysis reports
make report-coveralls # Upload coverage to Coveralls
```

## Event System Architecture

### Event Registration
Events are registered using dot notation with support for:
- Simple events: `user.create`
- Namespaced events: `user.profile.update`
- Wildcard matching: `user.*`, `*.save`, `*.*`

### Priority System
Listeners execute in priority order (highest to lowest):
- Multiple listeners at same priority execute in deterministic but undefined order
- Default priority is `EventManager::MID` (100)

### Event Propagation
- Listeners can throw `ExceptionStop` to halt further event processing
- `trigger()` returns count of successfully executed listeners
- Continue callbacks can control execution flow

## Testing Structure

Tests are located in `tests/` directory:
- `EventTest.php` - Core functionality tests
- `EventNamespacesTest.php` - Wildcard and namespace matching
- `EventPackageTest.php` - Package-level integration tests
- `phpbench/` - Performance benchmarks

## Code Standards

- PHP 8.2+ required
- Strict types declaration (`declare(strict_types=1)`)
- PSR-12 coding standard
- Full test coverage expected for new features
- Static analysis with PHPStan level max and Psalm

## Usage Patterns

When working with the EventManager:
1. Use descriptive namespaced event names (`entity.action.phase`)
2. Consider priority when order matters
3. Use `once()` for initialization events
4. Throw `ExceptionStop` to halt propagation when needed
5. Pass data via reference in arguments for listener communication
147 changes: 101 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@
[![Stable Version](https://poser.pugx.org/jbzoo/event/version)](https://packagist.org/packages/jbzoo/event/) [![Total Downloads](https://poser.pugx.org/jbzoo/event/downloads)](https://packagist.org/packages/jbzoo/event/stats) [![Dependents](https://poser.pugx.org/jbzoo/event/dependents)](https://packagist.org/packages/jbzoo/event/dependents?order_by=downloads) [![GitHub License](https://img.shields.io/github/license/jbzoo/event)](https://github.com/JBZoo/Event/blob/master/LICENSE)


The EventEmitter is a simple pattern that allows you to create an object that emits events, and allow you to listen to those events.
A lightweight PHP event manager library that provides a simple yet powerful pattern for event-driven development. Create objects that emit events and register listeners to handle them with support for priorities, namespaces, and wildcard matching.

### Install
## Features

- **Priority-based event handling** - Control execution order with built-in priority levels
- **Namespace support with wildcards** - Listen to `item.*`, `*.save`, or `*.*` patterns
- **Multiple callback types** - Closures, functions, static methods, and object methods
- **Event propagation control** - Stop event chains with `ExceptionStop`
- **One-time listeners** - Auto-removing listeners with `once()`
- **Reference parameter passing** - Communicate between listeners
- **High performance** - Optimized for speed with comprehensive benchmarks
- **PHP 8.2+ with strict types** - Modern PHP with full type safety

## Installation
```sh
composer require jbzoo/event
```

## Usage

### Simple example
### Quick Start
```php
use JBZoo\Event\EventManager;

Expand All @@ -28,7 +40,7 @@ $eManager->trigger('create');
```


### Set priority
### Priority-Based Execution
By supplying a priority, you are ensured that subscribers handle in a specific order. The default priority is EventManager::MID.
Anything below that will be triggered earlier, anything higher later.
If there are two subscribers with the same priority, they will execute in an undefined, but deterministic order.
Expand All @@ -54,8 +66,8 @@ $eManager->on('create', function () {
});
```

### Types of Callback
All default PHP callbacks are supported, so closures are not required.
### Callback Types
All standard PHP callable types are supported:
```php
$eManager->on('create', function(){ /* ... */ }); // Custom function
$eManager->on('create', 'myFunction'); // Custom function name
Expand All @@ -64,20 +76,20 @@ $eManager->on('create', [$object, 'Method']); // Method of instance
```


### Cancel queue of events
### Event Propagation Control
```php
use JBZoo\Event\ExceptionStop;

$eManager->on('create', function () {
throw new ExceptionStop('Some reason'); // Special exception for JBZoo/Event
});

$eManager->trigger('create'); // return 'Some reason' or TRUE if all events done
$eManager->trigger('create'); // Returns count of executed listeners
```


### Passing arguments
Arguments can be passed as an array.
### Passing Arguments
Event data can be passed to listeners as function arguments:
```php
$eManager->on('create', function ($entityId) {
echo "An entity with id ", $entityId, " just got created.\n";
Expand All @@ -96,7 +108,8 @@ $warnings = [];
$eManager->trigger('create', [$entityId, &$warnings]);
```

### Namespaces
### Namespace Wildcards
Use wildcards to listen to multiple related events:
```php
$eManager->on('item.*', function () {
// item.init
Expand Down Expand Up @@ -133,60 +146,102 @@ $eManager->trigger('item.save');
$eManager->trigger('item.save.after');
```

### One-Time Listeners
For events that should only be handled once:
```php
$eManager->once('app.init', function () {
echo "This will only run once, then auto-remove itself";
});

$eManager->trigger('app.init'); // Executes
$eManager->trigger('app.init'); // Does nothing - listener was removed
```

### Advanced Usage
```php
use JBZoo\Event\EventManager;

// Create a global event manager
EventManager::setDefault(new EventManager());
$globalManager = EventManager::getDefault();

## Summary benchmark info (execution time) PHP v7.4
All benchmark tests are executing without xdebug and with a huge random array and 100.000 iterations.
// Get summary of registered events
$summary = $eManager->getSummeryInfo();
// Returns: ['user.create' => 3, 'user.update' => 1, ...]

Benchmark tests based on the tool [phpbench/phpbench](https://github.com/phpbench/phpbench). See details [here](tests/phpbench).
// Remove specific listeners
$callback = function() { echo "test"; };
$eManager->on('test', $callback);
$eManager->removeListener('test', $callback);

Please, pay attention - `1μs = 1/1.000.000 of second!`
// Remove all listeners for an event
$eManager->removeListeners('test');

// Remove ALL listeners
$eManager->removeListeners();
```


## Performance Benchmarks

Extensive performance testing with 100,000 iterations shows excellent performance characteristics.
Benchmark tests use [phpbench/phpbench](https://github.com/phpbench/phpbench) - see detailed results in [`tests/phpbench`](tests/phpbench).

> **Note:** `1μs = 1/1,000,000 of a second` - these are microseconds!

**benchmark: ManyCallbacks**

subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff
--- | --- | --- | --- | --- | --- | --- | --- | ---
benchOneUndefined | undefined | 10 | 100000 | 0.65μs | 0.01μs | 1.00% | 6,291,456b | 1.00x
benchOneWithStarBegin | *.bar | 10 | 100000 | 0.67μs | 0.01μs | 1.44% | 6,291,456b | 1.04x
benchOneWithAllStars | \*.\* | 10 | 100000 | 0.68μs | 0.03μs | 4.18% | 6,291,456b | 1.04x
benchOneWithStarEnd | foo.* | 10 | 100000 | 0.68μs | 0.01μs | 1.24% | 6,291,456b | 1.04x
benchOneNested | foo.bar | 10 | 100000 | 43.23μs | 0.46μs | 1.07% | 6,291,456b | 66.56x
benchOneSimple | foo | 10 | 100000 | 45.07μs | 2.63μs | 5.83% | 6,291,456b | 69.39x
| subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| benchOneUndefined | undefined | 10 | 100000 | 0.65μs | 0.01μs | 1.00% | 6,291,456b | 1.00x |
| benchOneWithStarBegin | *.bar | 10 | 100000 | 0.67μs | 0.01μs | 1.44% | 6,291,456b | 1.04x |
| benchOneWithAllStars | \*.\* | 10 | 100000 | 0.68μs | 0.03μs | 4.18% | 6,291,456b | 1.04x |
| benchOneWithStarEnd | foo.* | 10 | 100000 | 0.68μs | 0.01μs | 1.24% | 6,291,456b | 1.04x |
| benchOneNested | foo.bar | 10 | 100000 | 43.23μs | 0.46μs | 1.07% | 6,291,456b | 66.56x |
| benchOneSimple | foo | 10 | 100000 | 45.07μs | 2.63μs | 5.83% | 6,291,456b | 69.39x |

**benchmark: ManyCallbacksWithPriority**

subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff
--- | --- | --- | --- | --- | --- | --- | --- | ---
benchOneUndefined | undefined | 10 | 100000 | 0.65μs | 0.01μs | 1.35% | 6,291,456b | 1.00x
benchOneNestedStarAll | \*.\* | 10 | 100000 | 0.67μs | 0.01μs | 1.34% | 6,291,456b | 1.03x
benchOneWithStarBegin | *.bar | 10 | 100000 | 0.67μs | 0.01μs | 1.10% | 6,291,456b | 1.04x
benchOneWithStarEnd | foo.* | 10 | 100000 | 0.68μs | 0.01μs | 1.13% | 6,291,456b | 1.05x
benchOneSimple | foo | 10 | 100000 | 4.54μs | 0.02μs | 0.35% | 6,291,456b | 7.03x
benchOneNested | foo.bar | 10 | 100000 | 4.58μs | 0.04μs | 0.81% | 6,291,456b | 7.10x
| subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| benchOneUndefined | undefined | 10 | 100000 | 0.65μs | 0.01μs | 1.35% | 6,291,456b | 1.00x |
| benchOneNestedStarAll | \*.\* | 10 | 100000 | 0.67μs | 0.01μs | 1.34% | 6,291,456b | 1.03x |
| benchOneWithStarBegin | *.bar | 10 | 100000 | 0.67μs | 0.01μs | 1.10% | 6,291,456b | 1.04x |
| benchOneWithStarEnd | foo.* | 10 | 100000 | 0.68μs | 0.01μs | 1.13% | 6,291,456b | 1.05x |
| benchOneSimple | foo | 10 | 100000 | 4.54μs | 0.02μs | 0.35% | 6,291,456b | 7.03x |
| benchOneNested | foo.bar | 10 | 100000 | 4.58μs | 0.04μs | 0.81% | 6,291,456b | 7.10x |

**benchmark: OneCallback**

subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff
--- | --- | --- | --- | --- | --- | --- | --- | ---
benchOneWithStarBegin | *.bar | 10 | 100000 | 0.69μs | 0.03μs | 4.00% | 6,291,456b | 1.00x
benchOneWithStarEnd | foo.* | 10 | 100000 | 0.70μs | 0.03μs | 4.22% | 6,291,456b | 1.00x
benchOneNestedStarAll | \*.\* | 10 | 100000 | 0.70μs | 0.04μs | 6.02% | 6,291,456b | 1.01x
benchOneUndefined | undefined | 10 | 100000 | 0.71μs | 0.05μs | 7.44% | 6,291,456b | 1.02x
benchOneSimple | foo | 10 | 100000 | 1.18μs | 0.03μs | 2.27% | 6,291,456b | 1.70x
benchOneNested | foo.bar | 10 | 100000 | 1.25μs | 0.03μs | 2.46% | 6,291,456b | 1.81x
| subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| benchOneWithStarBegin | *.bar | 10 | 100000 | 0.69μs | 0.03μs | 4.00% | 6,291,456b | 1.00x |
| benchOneWithStarEnd | foo.* | 10 | 100000 | 0.70μs | 0.03μs | 4.22% | 6,291,456b | 1.00x |
| benchOneNestedStarAll | \*.\* | 10 | 100000 | 0.70μs | 0.04μs | 6.02% | 6,291,456b | 1.01x |
| benchOneUndefined | undefined | 10 | 100000 | 0.71μs | 0.05μs | 7.44% | 6,291,456b | 1.02x |
| benchOneSimple | foo | 10 | 100000 | 1.18μs | 0.03μs | 2.27% | 6,291,456b | 1.70x |
| benchOneNested | foo.bar | 10 | 100000 | 1.25μs | 0.03μs | 2.46% | 6,291,456b | 1.81x |

**benchmark: Random**

subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff
--- | --- | --- | --- | --- | --- | --- | --- | ---
benchOneSimple | random.*.triggers | 10 | 100000 | 4.29μs | 0.33μs | 7.69% | 6,291,456b | 1.00x
| subject | groups | its | revs | mean | stdev | rstdev | mem_real | diff |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| benchOneSimple | random.*.triggers | 10 | 100000 | 4.29μs | 0.33μs | 7.69% | 6,291,456b | 1.00x |


## Unit tests and check code style
```sh
make update
make test-all
## Development

### Setup
```bash
make update # Install dependencies
```

### Testing
```bash
make test # Run PHPUnit tests
make test-all # Run tests + code style checks
make codestyle # Run all linters
```

## License

Expand Down
Loading