PHP code example of rcalicdan / event

1. Go to this page and download the library: Download rcalicdan/event library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

rcalicdan / event example snippets


// WRONG: Using events for validation
Event::on('user.register', function ($data) {
    if (!$validator->validate($data)) {
        return false; // Don't do this!
    }
});

// RIGHT: Validate before emitting
if (!$validator->validate($data)) {
    throw new ValidationException();
}
$user = User::create($data);
Event::emit('user.registered', $user); // Only emit what actually happened

// ACCEPTABLE: Performance optimization
Event::on('cache.check', function ($key) {
    if ($cache->has($key)) {
        return false; // Stop expensive cache rebuilding
    }
});

// Annotate your listener (recommended approach)
#[ListenTo('user.registered')]
class SendWelcomeEmail
{
    public function handle(UserDTO $user)
    {
        // Send welcome email
    }
}

// Discover all listeners once during bootstrap
ListenerDiscovery::discover(__DIR__ . '/src/Listeners');

// Emit events anywhere in your application
Event::emit('user.registered', new UserDTO(
    userId: $user->id,
    email: $user->email,
    registeredAt: new DateTimeImmutable()
));

readonly class UserDTO
{
    public function __construct(
        public string $userId,
        public string $email,
        public DateTimeImmutable $registeredAt,
    ) {}
}

Event::emit('user.registered', new UserDTO(
    userId: $user->id,
    email: $user->email,
    registeredAt: new DateTimeImmutable()
));

readonly class Money
{
    public function __construct(
        public int $amount,
        public string $currency
    ) {}
}

Event::emit('order.placed', [
    'orderId' => $order->id,
    'total' => $order->total,
    'items' => $order->items->count(),
]);

// Emit the entity
Event::emit('order.shipped', $order);

// Listeners should only read, never modify
Event::on('order.shipped', function (Order $order) {
    // GOOD: Reading state
    $tracking = $order->trackingNumber;
    
    // BAD: Modifying state
    // $order->markAsDelivered(); // Don't do this!
});

use Rcalicdan\Event\Attributes\ListenTo;
use Rcalicdan\Event\Attributes\ListenOnce;
use Rcalicdan\Event\ListenerDiscovery;

// Class-level attribute
#[ListenTo('user.registered', priority: 10)]
class SendWelcomeEmail
{
    public function handle(UserDTO $user)
    {
        // Send email logic
    }
}

// Multiple events on one class
#[ListenTo('order.placed', method: 'onOrderPlaced')]
#[ListenTo('order.cancelled', method: 'onOrderCancelled')]
class OrderNotificationService
{
    public function onOrderPlaced(OrderDTO $order)
    {
        // Handle order placed
    }
    
    public function onOrderCancelled(OrderDTO $order)
    {
        // Handle order cancelled
    }
}

// Method-level attributes
class PaymentProcessor
{
    #[ListenTo('payment.received', priority: 5)]
    public function processPayment(PaymentDTO $payment)
    {
        // Process payment
    }
    
    #[ListenOnce('app.initialized')]
    public function setupPaymentGateway()
    {
        // One-time initialization
    }
}

// Function-level attributes
#[ListenTo('user.login')]
function logUserActivity(UserDTO $user): void
{
    // Log activity
}

// Discover and register all listeners once during bootstrap
ListenerDiscovery::discover(
    directory: [
        __DIR__ . '/src/Listeners',
        __DIR__ . '/src/Subscribers',
        __DIR__ . '/src/EventHandlers',
    ],
    failFast: false,                    // Resilient mode for production
    cachePath: __DIR__ . '/var/cache',  // Enable caching
    refreshCache: true,                 // Auto-refresh in development
    container: $container,              // PSR-11 container for DI
    emitter: null                       // Use default emitter
);

use Rcalicdan\Event\Event;

// Register listeners manually
Event::on('user.login', function (UserDTO $user) {
    logActivity($user);
});

// Emit from anywhere
Event::emit('user.login', $user);

use Rcalicdan\Event\EventEmitterTrait;

class OrderProcessor
{
    use EventEmitterTrait;
    
    public function process(Order $order)
    {
        // Business logic
        $order->markAsPaid();
        
        // Emit events
        $this->emit('order.processed', new OrderDTO(...));
        $this->emit('inventory.reserved', $order->items);
    }
}

// Use it
$processor = new OrderProcessor();
$processor->on('order.processed', function (OrderDTO $order) {
    echo "Order {$order->orderId} processed!";
});

use Rcalicdan\Event\EventEmitter;

$emitter = new EventEmitter();

$emitter->on('data.received', function ($data) {
    processData($data);
});

$emitter->emit('data.received', $payload);

use Rcalicdan\Event\EventEmitterInterface;
use Rcalicdan\Event\Event;

class AsyncEventEmitter implements EventEmitterInterface
{
    // Custom implementation with async processing,
    // message queue integration, distributed events, etc.
}

// Option 1: Set globally
Event::setInstance(new AsyncEventEmitter());

// Option 2: Use with listener discovery
ListenerDiscovery::discover(
    directory: __DIR__ . '/src/Listeners',
    emitter: new AsyncEventEmitter()
);

use Rcalicdan\Event\Event;

// Development: fail fast on errors
Event::failFast();

// Production: resilient error handling
Event::resilient();

// Prevent memory leaks
Event::setMaxListeners(100);

use Rcalicdan\Event\Event;
use Rcalicdan\Event\Attributes\ListenTo;
use Rcalicdan\Event\Attributes\ListenOnce;
use Rcalicdan\Event\ListenerDiscovery;

// Define immutable event DTOs
readonly class OrderDTO
{
    public function __construct(
        public string $orderId,
        public float $total,
        public DateTimeImmutable $placedAt,
    ) {}
}

// Attribute-based listeners (recommended)
#[ListenTo('order.placed', priority: 10)]
class NotifyWarehouse
{
    public function handle(OrderDTO $order)
    {
        // Notify warehouse system
    }
}

#[ListenTo('order.placed', priority: 5)]
#[ListenTo('order.shipped')]
class SendCustomerNotification
{
    public function handle(OrderDTO $order)
    {
        // Send email to customer
    }
}

#[ListenOnce('app.initialized')]
function setupEventTracking(): void
{
    // One-time initialization
}

// Wildcard listener
#[ListenTo('order.*')]
class OrderLogger
{
    public function handle(OrderDTO $order)
    {
        logEvent('order_event', $order);
    }
}

// Type-safe events with enums
enum OrderEvents: string {
    case Placed = 'order.placed';
    case Shipped = 'order.shipped';
    case Delivered = 'order.delivered';
}

#[ListenTo(OrderEvents::Placed->value)]
class ProcessPayment
{
    public function handle(OrderDTO $order)
    {
        // Process payment
    }
}

// Bootstrap: discover all listeners once
ListenerDiscovery::discover(
    directory: __DIR__ . '/src/Listeners',
    cachePath: __DIR__ . '/var/cache',
    refreshCache: true
);

// Emit events anywhere in your application
Event::emit('order.placed', new OrderDTO(
    orderId: $order->id,
    total: $order->total,
    placedAt: new DateTimeImmutable()
));

Event::emit(OrderEvents::Placed, new OrderDTO(...));