Introduction
One of the real challenges in building any type of framework, core or application is making it possible for the developers to hook into the business logic at specific points. Since PHP is not event based, nor it works with interrupts you have to come up an alternative.
The test case
Lets assume we are the main developers of a webshop framework. Programmers can use our framework to build complete webshops. Programmers can manage the orders that are placed on the webshop with the order class. The order class is part of our framework and we don’t want it to be extended by any programmer. However we don’t want to limit to programmers in their possibilities to hook into the orders process.
For example programmers should be able to send an email to the webshopowner if an order changes from one specific delivery status to another. This functionality is not part of the default behavior in our framework and is custom for the progammers webshop implementation.
Like said before, PHP doesn’t provide interrupts or real events so we need to come up with another way to implement hooks into our application. Lets take a look at the observer pattern.
Implementing the Observer pattern
The observer pattern is a design-pattern that describes a way for objects to be notified to specific state-changes in objects of the application.
For the first implementation we can use SPL. The SPL provides in two simple objects:
SPLSubject
- attach (new observer to attach)
- detach (existing observer to detach)
- notify (notify all observers)
SPLObserver
- update (Called from the subject (i.e. when it’s value has changed).
iOrderRef = $iOrderRef;
// Get order information from the database or an other resources
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param SplObserver $oObserver
* @return void
*/
public function attach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param SplObserver $oObserver
* @return void
*/
public function detach(SplObserver $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notify()
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function delete()
{
$this->notify();
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notify();
// ...
$this->iStatus = $iStatus;
// ...
$this->notify();
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements SplObserver
{
/**
* Previous orderstatus
* @var int
*/
protected $iPreviousOrderStatus;
/**
* Current orderstatus
* @var int
*/
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oSubject
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(SplSubject $oSubject)
{
if(!$oSubject instanceof Order) {
return;
}
if(is_null($this->iPreviousOrderStatus)) {
$this->iPreviousOrderStatus = $oSubject->getStatus();
} else {
$this->iCurrentOrderStatus = $oSubject->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oSubject->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attach(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->delete();
?>
There are several problems with the implementation above. To most important disadvantage is that we have only one update method in our observer. In this update method we don’t know when and why we are getting notified, just that something happened. We should keep track of everything that happens in the subject. (Or use debug_backtrace… just joking, don’t even think about using it that way ever!).
Taking it a step further, events
Lets take a look at the next example, we will extend the Observer implementation with some an additional parameter for the eventname that occured.
Finishing up, optional data
iOrderRef = $iOrderRef;
// Get order information from the database or something else...
$this->iStatus = Order::STATUS_SHIPPED;
}
/**
* Attach an observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function attachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (isset($this->aObservers[$sHash])) {
throw new Exception('Observer is already attached');
}
$this->aObservers[$sHash] = $oObserver;
}
/**
* Detach observer
*
* @param Observer_Interface $oObserver
* @return void
*/
public function detachObserver(Observer_Interface $oObserver)
{
$sHash = spl_object_hash($oObserver);
if (!isset($this->aObservers[$sHash])) {
throw new Exception('Observer not attached');
}
unset($this->aObservers[$sHash]);
}
/**
* Notify the attached observers
*
* @param string $sEvent, name of the event
* @param mixed $mData, optional data that is not directly available for the observers
* @return void
*/
public function notifyObserver($sEvent, $mData=null)
{
foreach ($this->aObservers as $oObserver) {
try {
$oObserver->update($this, $sEvent, $mData);
} catch(Exception $e) {
}
}
}
/**
* Add an order
*
* @param array $aOrder
* @return void
*/
public function add($aOrder = array())
{
$this->notifyObserver('onAdd');
}
/**
* Return the order reference number
*
* @return int
*/
public function getRef()
{
return $this->iOrderRef;
}
/**
* Return the current order status
*
* @return int
*/
public function getStatus()
{
return $this->iStatus;
}
/**
* Update the order status
*/
public function updateStatus($iStatus)
{
$this->notifyObserver('onBeforeUpdateStatus');
// ...
$this->iStatus = $iStatus;
// ...
$this->notifyObserver('onAfterUpdateStatus');
}
}
/**
* Order status handler, observer that sends an email to secretary
* if the status of an order changes from shipped to delivered, so the
* secratary can make a phone call to our customer to ask for his opinion about the service
*
* @package Shop
*/
class OrderStatusHandler implements Observer_Interface
{
protected $iPreviousOrderStatus;
protected $iCurrentOrderStatus;
/**
* Update, called by the observable object order
*
* @param Observable_Interface $oObservable
* @param string $sEvent
* @param mixed $mData
* @return void
*/
public function update(Observable_Interface $oObservable, $sEvent, $mData=null)
{
if(!$oObservable instanceof Order) {
return;
}
switch($sEvent) {
case 'onBeforeUpdateStatus':
$this->iPreviousOrderStatus = $oObservable->getStatus();
return;
case 'onAfterUpdateStatus':
$this->iCurrentOrderStatus = $oObservable->getStatus();
if($this->iPreviousOrderStatus === Order::STATUS_SHIPPED && $this->iCurrentOrderStatus === Order::STATUS_DELIVERED) {
$sSubject = sprintf('Order number %d is shipped', $oObservable->getRef());
//mail('secratary@example.com', 'Order number %d is shipped', 'Text');
echo 'Mail sended to the secratary to help her remember to call our customer for a survey.';
}
}
}
}
$oOrder = new Order(26012011);
$oOrder->attachObserver(new OrderStatusHandler());
$oOrder->updateStatus(Order::STATUS_DELIVERED);
$oOrder->add();
?>
Now we are able to take action on different events that occur.
Disadvantages
Although this implementation works quite well there are some drawbacks. One of those drawbacks is that we need to dispatch an event in our framework, if we don’t programmers can’t hook into our application. Triggering events everywhere give us a small performance penalty however I do think this way of working gives the programmers a nice way to hook into your application on those spots that you want them to hook in.
Just for the record
Notice that this code is just an example and can still use some improvements, for example: each observer is initialized even it will maybe never be notified, therefore I suggest to make use of lazy in some cases for loading the objects. There are other systems to hook into an application, more to follow!
I’m not sure why but this blog is loading incredibly slow for me.
Is anyone else having this issue or is it a problem on my end?
I’ll check back later and see if the problem still exists.
Бездепозитный бонус Казино, предлагающие бездепозитные бонусы, как гостеприимные хозяева, распахивают двери перед новичками и предлагают им оценить все прелести своего заведения. Это своеобразный жест доброй воли, который позволяет завоевать доверие игроков и превратить их в постоянных клиентов. Это умный маркетинговый ход, который работает в пользу обеих сторон. Бездепозитный бонус
Психотерапевт Белгород. batmanapollo.ru 516 оценок
скачат мостбет https://mostbet11029.ru
купить санта фе Купить Ауди: Современные технологии и изысканный дизайн Audi – это бренд, известный своими современными технологиями, изысканным дизайном и высоким уровнем комфорта.
мостбет кыргызстан мостбет кыргызстан
Какой сегодня праздник https://www.novorjev.ru .
Пронедра http://www.novorjev.ru .
Погода https://novorjev.ru .
Please let me know if you’re looking for a writer for your blog.
You have some really great posts and I feel I would
be a good asset. If you ever want to take some of the load
off, I’d absolutely love to write some material for your blog in exchange
for a link back to mine. Please shoot me an e-mail if interested.
Thank you!
Peculiar article, exactly what I wanted to find.
Купить диплом об образовании!
Мы предлагаем дипломы любой профессии по приятным ценам— alldirectorys.ru
https://b2tor2.cc/bs2web_at.html
Heya! I understand this is sort of off-topic however
I had to ask. Does managing a well-established website such as yours
take a massive amount work? I’m completely new to writing
a blog however I do write in my diary daily. I’d like to start a blog so I can share my personal experience and views online.
Please let me know if you have any kind of ideas or tips for brand new aspiring bloggers.
Thankyou!
I constantly spent my half an hour to read this webpage’s posts
everyday along with a cup of coffee.
Заказать диплом университета!
Мы изготавливаем дипломы психологов, юристов, экономистов и любых других профессий по приятным тарифам— vuzdiplom.ru
купить санта фе Киа Карнивал: Семейный минивэн для любых задач Kia Carnival – это просторный и функциональный минивэн, идеально подходящий для больших семей и активного отдыха.
London and Surrey outdoor services
Professional Deck and Furniture Restoration іn London and Surrey
Lօoking fοr professional care for yoᥙr garden? Οur services in outdoor furniture restoration and
decking cleaning іn London and Surrey are bacҝeԀ by 20+ yeaes of expertise.
Reach ᥙs at 01784 456 475.
unique kids clothing Bright and fun bird designs for kids! Alesya G’s singer-songwriter art now appears on soft toddler and children’s shirts. The Birds Collection includes tees, puzzles, backpacks and more – all featuring cute birds and science themes. Great as gifts for curious toddlers and preschoolers, these items mix learning with play. Shop kids’ bird t-shirts and accessories for your little explorer today!
Купить документ института вы сможете у нас в столице. Заказать диплом университета по невысокой стоимости можно, обращаясь к проверенной специализированной компании. munchkin.flybb.ru/viewtopic.phpf=7&t=5423
займ микрозаймы без процентов
Hi to every body, it’s my first pay a visit of this weblog; this
website consists of awesome and truly excellent information for readers.
такси прага аэропорт такси прага аэропорт
Приобрести диплом о высшем образовании!
Мы изготавливаем дипломы любых профессий по доступным ценам— [url=http://momu2.ru/]momu2.ru[/url]
хотите сделать утепление https://cvet-dom.ru/dom_i_postroika/stroika_otdelka-i-kommunikacii/zachem-uteplyat-mansardnuyu-kryshu-i-pochemu-poliuretan
Купить документ о получении высшего образования вы имеете возможность в нашей компании. Купить диплом института по невысокой цене можно, обратившись к надежной специализированной компании. poeskovek.flybb.ru/viewtopic.phpf=2&t=701
Гороскоп https://www.pechory-online.ru .
новости дня https://pechory-online.ru .
highest payout online casino highest payout online casino .
Лунные день сегодня https://pechory-online.ru .
It is appropriate time to make some plans for the future and it’s time to be happy.
I have read this post and if I could I want to suggest you some interesting things or tips.
Maybe you could write next articles referring to this
article. I desire to read more things about it!
купить авто с пробегом Киа Карнивал: Семейный минивэн для любых задач Kia Carnival – это просторный и функциональный минивэн, идеально подходящий для больших семей и активного отдыха.
Купить документ университета вы имеете возможность у нас в столице. Купить диплом университета по доступной цене вы сможете, обращаясь к надежной специализированной компании. [url=http://nonoclick.com/read-blog/2397_mozhno-li-kupit-attestat-za-9-klass.html/]nonoclick.com/read-blog/2397_mozhno-li-kupit-attestat-za-9-klass.html[/url]
We’re a group of volunteers and opening a new scheme in our community.
Your web site offered us with useful info to
work on. You’ve done a formidable process and our whole neighborhood will be thankful to you.
safe online casino australia safe online casino australia .
no deposit pokies real cash fast payouts https://maryvaleqld.com.au/real-money-pokies/no-deposit-bonus// .
Pretty! This has been an extremely wonderful article.
Thank you for providing this information.
Incredibly individual friendly website. Immense information readily available on few clicks on.
https://www.zvami.tv
услуги такси в праге до аэропорта дешевое такси в аэропорт прага
займ на карту без отказа микрозаймы без процентов
хотите сделать утепление https://mon24.su/uteplenie-penopoliuretanom-garazha-stoit-li-ispolzovat-jetot-material-dlja-avtoljubitelej/
Лунный календарь http://topoland.ru/ .
What’s Happening i am new to this, I stumbled upon this I’ve found
It absolutely useful and it has aided me out loads. I hope to give a contribution & assist different customers like its helped me.
Great job.
https://a-bsme.at/blacksprut_bs2best.html
новости дня inforigin.ru .
What’s Taking place i’m new to this, I stumbled upon this
I’ve found It absolutely helpful and it has helped me out loads.
I am hoping to give a contribution & assist other users like its aided me.
Good job.
В17 психология. Психолог 163 895 оценок
fast lean pro benefits Upon my pal’s tip, I decided
to attempt Fast Lean Pro, and it has actually proven to
be a game-changer for me. This product has properly
aided me in shedding those stubborn extra pounds that
I struggled to lose via conventional methods like diet and workout.
The mix of eco-friendly tea essence and Garcinia cambogia extract shows up to have a
positive effect on my metabolism, and I value
that-natural. Furthermore, I have experienced better
food digestion as an unforeseen advantage. Fast Lean Pro is currently an important part of my
daily program enhancing my confidence and overall health.
For any person seeking a credible weight monitoring option, I highly
suggest offering Fast Lean Pro a chance.
Wonderful, what a blog it is! This website gives valuable facts to us, keep it up.
elegant swimwear Create a romantic vibe with Avec Amour by Alesya G – her swimwear and tees are infused with soft Parisian flair. Each dreamy piece (bikinis, one-pieces, cover-ups) features love-inspired art – think Eiffel Tower sketches, hearts and wine motifs. Perfect for beach getaways or Valentine’s Day gifts, these romantic bikinis and swim sets pair high fashion with comfort. Fall in love with our French-inspired designs!