R1KO / Observer

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Observer

Please note that this #@%^^@#$ (library) is made for educational purposes. Do not use it in real projects if your health is dear to you.

Peace :3

Inspired By

System Requirements

  • PHP NTS >= 7.4
  • ext-ffi

Installation

I am too lazy to upload this library on the packagist and produce entropy. Therefore, you will have to press the "download" button yourself.

Thank you!

Usage

For example, we have the following code:

class Vector2
{
    public float $x = 0.0;
    public float $y = 0.0;
}

$vec2 = new Vector2();

Now we want to hang certain behavior on it when changing fields.

use \Serafim\Observer\Observer;

$observer = Observer::create($vec2);
$observer->x->subscribe(fn ($to, $from) => print "vec2->x changed from $from to $to\n");
$observer->y->subscribe(fn ($to, $from) => print "vec2->y changed from $from to $to\n");

$vec2->x = 42;
// "vec2->x changed from 0 to 42"

$vec2->y = 23;
// "vec2->y changed from 0 to 23"

API

New Observer Context

$observer = Observer::create($anyObject);

Create Subscription

$subscription = $observer->field_name
    ->subscribe(function ($value, $oldValue) {
        var_dump('changed in object: ', $this);
        var_dump('old value: ' . $oldValue);
        var_dump('new value: ' . $value);
    });

// OR $observer->subscribe('field_name', $callback);

Delete Subscription

$subscription = $observer->field_name->subscribe($callback);

$subscription->dispose();

Or alternative method

$subscription = $observer->field_name->subscribe($callback);

$observer->unsubscribe($subscription);

Delete All Subscriptions

$observer->field_name->unsubscribeAll();

Quantity Management

$subscription = $observer->field_name->subscribe($callback);

$subscription->endless();  // [DEFAULT] Subscription will be called every time the value is changed
$subscription->once();     // The subscription will be called ONCE and then deleted
$subscription->twice();    // The subscription will be called TWICE and then deleted
$subscription->times(xxx); // The subscription will be called XXX TIMES and then deleted

Notifications

$subscription = $observer->field_name
    ->subscribe(fn ($val) => print "value is $val\n");

$subscription->notify(42);
// "value is 42"

$subscription->notify(23);
// "value is 23"

Recursive Calls

$observer = Observer::create($vec2);
$observer->x->subscribe(fn ($val) => $this->x = $val);

$vec2->x = 23;

var_dump($vec2);
// object(Vector2)#3 (2) {
//   ["x"]=>
//   float(23)
//   ["y"]=>
//   float(0)
// }

However, do not do as follows

$observer = Observer::create($vec2);
$observer->x->subscribe(fn ($val) => $this->x = $val + 1);
                                             // ^^^^^^^^^

$vec2->x = 23;
// Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 4194304 bytes)

Known Issues

  1. Doesn't work in PHP ZTS mode.

  2. Unstable behavior on PHP 8.0+

  3. Discloses fields encapsulation

$test = new Example();

Observer::create($test)
    ->privateProperty
    ->subscribe(fn (...) => ...);

$test->privateProperty = 23; // No error occurs
  1. Breaks __set "magic" method (It just doesn't work).

  2. DCE\Inlining bug (or wtf?):

class Counter
{
    private int $val = 0;
    public function inc()
    {
        $this->val++;
    }
    public function add(int $val)
    {
        $this->val += $val;
    }
}

$counter = new Counter();

Observer::create($counter)
    ->val->subscribe(fn ($val) => print "value is $val");

$counter->add(1); // OK (prints "value is 1")
$counter->add(1); // Err (prints nothing if call it twice)

$counter->inc();  // Err (never prints anything)

About


Languages

Language:PHP 51.1%Language:C 48.9%