PHPackages                             jgswift/observr - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. jgswift/observr

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

jgswift/observr
===============

PHP 5.5+ event layer

0.2.5(11y ago)03224MITPHPPHP &gt;=5.5

Since May 18Pushed 11y ago1 watchersCompare

[ Source](https://github.com/jgswift/observr)[ Packagist](https://packagist.org/packages/jgswift/observr)[ RSS](/packages/jgswift-observr/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (9)Dependencies (3)Versions (10)Used By (4)

observr
=======

[](#observr)

PHP 5.5+ event layer

[![Build Status](https://camo.githubusercontent.com/743d91742b3f04eab6e4794f77bdf168ef3c66304edba40d8d2a068046c0f732/68747470733a2f2f7472617669732d63692e6f72672f6a6773776966742f6f6273657276722e706e673f6272616e63683d6d6173746572)](https://travis-ci.org/jgswift/observr)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/614db42f61480ed236eb8fcc1743c53eb7c4da69e1b3aaeccb51fc14dc06a62e/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a6773776966742f6f6273657276722f6261646765732f7175616c6974792d73636f72652e706e673f733d38376134343234323333396232623030376466313664353834376230366330323436353030393331)](https://scrutinizer-ci.com/g/jgswift/observr/)[![Latest Stable Version](https://camo.githubusercontent.com/5ab9c7a20d79284a4583c736cb180a20c37d3e5b4c682c7b5b7bc60c06ac1620/68747470733a2f2f706f7365722e707567782e6f72672f6a6773776966742f6f6273657276722f762f737461626c652e737667)](https://packagist.org/packages/jgswift/observr)[![License](https://camo.githubusercontent.com/f3c26cbf1f8a21ac59c6b1d070ac8b71b1948973a63f39a3eb37d58fb3055ee0/68747470733a2f2f706f7365722e707567782e6f72672f6a6773776966742f6f6273657276722f6c6963656e73652e737667)](https://packagist.org/packages/jgswift/observr)[![Coverage Status](https://camo.githubusercontent.com/c63187f7ea0139bf611ff315ecfe66ce28acc59f038e3f2e1222264f30a76dbb/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6a6773776966742f6f6273657276722f62616467652e706e673f6272616e63683d6d6173746572)](https://coveralls.io/r/jgswift/observr?branch=master)

Description
-----------

[](#description)

observr is a generic event layer that provides a flexible foundation for event handling in a domain-agnostic and non-intrusive way.

Installation
------------

[](#installation)

Install via cli using [composer](https://getcomposer.org/):

```
php composer.phar require jgswift/observr:0.2.*
```

Install via composer.json using [composer](https://getcomposer.org/):

```
{
    "require": {
        "jgswift/observr": "0.2.*"
    }
}
```

Dependency
----------

[](#dependency)

- php 5.5+
- [react/promise](https://github.com/reactphp/promise)

Usage
-----

[](#usage)

### Subject

[](#subject)

The Subject layer is a flexible interface/trait combination that provides a generic observer pattern implementation.

#### Basic example

[](#basic-example)

```
class User implements observr\SubjectInterface
{
    use observr\Subject;
}

$user = new User;
$user->attach("login",function($sender,$e) {
    return "login successful";
});

var_dump($user->setState("login")); // returns "login successful"
```

#### State Change

[](#state-change)

`observr\Event` delivers a combination `EventInterface` and `EventAwareInterface` to the observing callbacks and can be used to define pass-thru state variables.

```
$user = new User;
$user->attach("login",function($sender,$e) {
    $e->cancel();  // manual cancellation
});

$event = new observr\Event($user);
$user->setState("login",$event)

var_dump($event->isCanceled()); // returns true
```

To implement a custom event interface just inherit `observr\Event` or implement `EventInterface` and `EventAwareInterface`

#### EventInterface (abbr.)

[](#eventinterface-abbr)

State status and exception container

```
interface EventInterface {
    public function isComplete();

    public function isSuccess();

    public function isFailure();

    public function isCanceled();

    public function getException();

    public function setException(\Exception $exception);
}
```

#### EventAwareInterface (abbr.)

[](#eventawareinterface-abbr)

Performs state changes for `EventInterface`

```
interface EventAwareInterface {
    public function cancel(EventInterface $event = null);

    public function complete(EventInterface $event);

    public function fail(EventInterface $event);

    public function succeed(EventInterface $event);
}
```

#### Event Namespacing

[](#event-namespacing)

In order to handle events differently depending on package behavior it is possible to `attach`/`detach` with namespaces.

```
$user = new User;

$user->attach('login',function($sender,$e) {
    echo 'default login';
});

$user->attach('login.myNamespace',function($sender,$e) {
    echo 'my custom login';
});

$user->setState('login'); // echo 'default login' & 'my custom login'

$user->detach('login.myNamespace'); // removes only the namespaced handler

$user->setState('login'); // echo 'default login'
```

#### Success, Failure, Complete, Cancel

[](#success-failure-complete-cancel)

`observr\Event` also implements the observer pattern itself and can be used to validate event results. The validation constants are `COMPLETE`, `FAILURE`, `SUCCESS`, and `CANCEL`

- `COMPLETE` is notified when all observers fire without failure
- `FAILURE` is notified when any observer throws an exception
- `SUCCESS` is notified every time the state is changed without failure or cancellation
- `CANCEL` is notifier when any observer invokes cancellation

```
$user = new User;
$event = new observr\Event($user);

$user->attach("login",function($sender,$e) {
    // success with no cancellation or errors, default behavior
});

$event->attach(observr\Event::COMPLETE,function() {
    echo 'COMPLETE';
});

$event->attach(observr\Event::SUCCESS,function() {
    echo 'SUCCESS';
});

$user->setState("login",$event); // everything worked!
// invokes ...
// COMPLETE
// SUCCESS

$user->attach("login",function($sender,$e) {
    $e->cancel(); // cancels the event
});

$event->attach(observr\Event::CANCEL,function() {
    echo 'CANCELED';
});

$user->setState("login",$event); // manual cancellation
// invokes ...
// COMPLETE
// CANCEL

$user->attach("login",function($sender,$e) {
    throw new \Exception; // causes fault
});

$event->attach(observr\Event::FAILURE,function() {
    echo 'FAILURE'
});

$user->setState("login",$event); // throws exception
// invokes ...
// FAILURE
```

### Emitter

[](#emitter)

Emitter is a Subject where events are exposed into individual objects

#### Basic Emitter

[](#basic-emitter)

```
class Button implements observr\SubjectInterface {
    use observr\Subject;
}

$button = new Button;

$click = new observr\Emitter('click');

$button->setState($click, function($sender,$e) {
    echo 'CLICKED!';
});

$click($button); // prints 'CLICKED'!
```

#### EmitterInterface (abbr.)

[](#emitterinterface-abbr)

```
interface EmitterInterface extends SubjectInterface {
    public function getName();

    public function emit($e = null);

    public function on(callable $callable);

    public function bind(callable $callable);

    public function unbind(callable $callable);

    public function map(callable $callable);

    public function filter(callable $callable);

    public function __toString();
}
```

#### Combining Emitters

[](#combining-emitters)

```
class Button {
    function __construct() {
        $this->click = new observr\Emitter('click');
        $this->mouseup = new observr\Emitter('mouseup');
        $this->mousedown = new observr\Emitter('mousedown');
    }
}

$button = new Button;

$combinedClick = $button->click->map(function($sender, $e) {
    /* extra mapping */
})->merge($button->mousedown->map(function($sender,$e) {
    /* extra mapping */
}))->merge($button->mouseup->map(function($sender,$e) {
    /* extra mapping */
}));

$combinedClick($button); // performs click, mousedown & mouseup all together
```

#### Filtering

[](#filtering)

Filtering allows mapping procedures to be applied selectively

```
$sending = $button->click
  ->filter(function($button,$e) {
    if($button instanceof Button) { // only changes Button to "Sending..."
        return true;
    }

    return false;
})->map(function($button,$e) {
    $button->value = 'Sending...';
});

$sending($button); // triggers click and changes button text to "Sending..."
```

### Streaming

[](#streaming)

A stream provides an easy way to wrap around multiple subjects at once and listen to many events.

#### Basic

[](#basic)

```
$bob = new User
$john = new User;

$stream = new observr\Stream('login');

// instruct stream to watch our user login events
$stream->watch($bob);
$stream->watch($john);

$c = 0;
$stream->attach(function($sender,$e=null)use(&$c) {
    $c++; // called twice, this is where we intercept the event
});

// open stream
$stream->open();

// trigger some fake logins
$bob->setState('login');
$john->setState('login');

// close stream
$stream->close();

var_dump($c); // 2
```

#### StreamInterface (abbr.)

[](#streaminterface-abbr)

```
interface StreamInterface {
    public function close();

    public function getSubjects();

    public function isOpen();

    public function open();

    public function watch($pointer);

    public function unwatch($pointer);

    public function isWatching($pointer);
}
```

Related Package(s)
------------------

[](#related-packages)

- [jgswift/detectr](http://github.com/jgswift/detectr) - complex event processor

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~25 days

Recently: every ~17 days

Total

9

Last Release

4169d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e60e96f18d8a9dc2aff1363eedbaf210acc96666e7497d2a83d5a416ef397295?d=identicon)[jgswift](/maintainers/jgswift)

---

Top Contributors

[![jgswift](https://avatars.githubusercontent.com/u/661738?v=4)](https://github.com/jgswift "jgswift (51 commits)")

---

Tags

phptraitobservermagic

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jgswift-observr/health.svg)

```
[![Health](https://phpackages.com/badges/jgswift-observr/health.svg)](https://phpackages.com/packages/jgswift-observr)
```

###  Alternatives

[kkszymanowski/traitor

Add a trait use statement to existing PHP class

1305.2M16](/packages/kkszymanowski-traitor)[ebidtech/collection

A set of interfaces and traits to speed up the creation of collections

13119.8k6](/packages/ebidtech-collection)[iteks/laravel-enum

A comprehensive Laravel package providing enhanced enum functionalities, including attribute handling, select array conversions, and fluent facade interactions for robust enum management in Laravel applications.

2516.7k](/packages/iteks-laravel-enum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
