Safeguard for observers to prevent problems in the invocation order.
Install using composer:
composer require stratadox/observation-queue
Use this if you have situations where observers and observables are heavily used.
Observers, by default, come with a few pretty tricky gotcha's. Reentry, for instance, may cause bugs that can get pretty difficult to find.
Let's take a look at the following scenario:
We have two observables, Foo and Bar.
Observer A observes Foo, triggering Bar on update.
Observer B observes both Foo and Bar.
Foo gets triggered.
Since Observer A
got registered to Foo
before Observer B
got registered,
Observer A
is updated first.
Updating Observer A
triggers Bar
, which in turn leads to Bar
updating its
subscribers.
Makes sense for far, right?
But here's the tricky part: At this point, Foo
has not yet updated Observer B
!
Of course, Observer B
will eventually get updated by Foo
. But only after
receiving the update from Bar
.
In situations where an Observer can trigger an update to an Observable, and the execution order of the relevant observers is of some importance, it may be wise to use the ObservationQueue.
The ObservationQueue is a queue of all the messages that still need to be sent to the observers. Observables add their items to the queue, and proceed to trigger the execution of the queue.
Due to this queueing layer, observer notifications are processed in the order in which the observables got triggered.
Although the monetary price of the software is zero, using this mechanism does introduce some shared mutable state. In order for the queue to have any effect, multiple observables need to be given access.
Normally, updating the subscribers of an Observable would go roughly like this:
foreach ($this->subscribers as $subscriber) {
$subscriber->notify($this);
}
When using an observation queue, instead use:
foreach ($this->subscribers as $subscriber) {
$this->queue->add($subscriber, 'notify', $this);
}
$this->queue->trigger();