PHP hook, building hooks in your application
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!
купить диплом продавца [url=https://rudik-diplom14.ru/]купить диплом продавца[/url] .
Diplomi_afea
3 Oct 25 at 10:46 am
Все про ремонт https://lesnayaskazka74.ru и строительство: от идеи до сдачи. Пошаговые гайды, электрика и инженерия, отделка, фасады и кровля. Подбор подрядчиков, сметы, шаблоны актов и договоров. Дизайн-инспирации, палитры, мебель и свет.
Williamcrype
3 Oct 25 at 10:47 am
Мы выбрали кухню на заказ и не пожалели. Проект разработали быстро, предложили разные варианты фасадов и фурнитуры. Доставка и монтаж прошли без проблем, кухня получилась современной и удобной – https://kuhni-v-dom.ru/
Eugeniostync
3 Oct 25 at 10:47 am
The hype around $MTAUR presale is justified—over 1M USDT in days. Unlocking boosts and outfits with tokens adds depth to gameplay. This is crypto meeting casual gaming perfectly.
minotaurus ico
WilliamPargy
3 Oct 25 at 10:48 am
купить диплом в юрге [url=https://rudik-diplom3.ru]купить диплом в юрге[/url] .
Diplomi_kjei
3 Oct 25 at 10:48 am
Golden Dice 3
Michaelrow
3 Oct 25 at 10:50 am
купить диплом [url=www.rudik-diplom15.ru/]купить диплом[/url] .
Diplomi_qvPi
3 Oct 25 at 10:50 am
прогнозы [url=http://prognozy-na-sport-11.ru/]прогнозы[/url] .
prognozi na sport_uvPa
3 Oct 25 at 10:50 am
новости футбола [url=https://novosti-sporta-15.ru]https://novosti-sporta-15.ru[/url] .
novosti sporta_xuma
3 Oct 25 at 10:50 am
This info is worth everyone’s attention. How can I find
out more?
89BET
3 Oct 25 at 10:52 am
новости тенниса [url=https://novosti-sporta-17.ru/]novosti-sporta-17.ru[/url] .
novosti sporta_esOi
3 Oct 25 at 10:54 am
Все про ремонт https://lesnayaskazka74.ru и строительство: от идеи до сдачи. Пошаговые гайды, электрика и инженерия, отделка, фасады и кровля. Подбор подрядчиков, сметы, шаблоны актов и договоров. Дизайн-инспирации, палитры, мебель и свет.
Williamcrype
3 Oct 25 at 10:55 am
спортивные трансляции [url=https://novosti-sporta-15.ru/]https://novosti-sporta-15.ru/[/url] .
novosti sporta_numa
3 Oct 25 at 10:55 am
точный прогноз на спорт [url=http://www.prognozy-na-sport-11.ru]http://www.prognozy-na-sport-11.ru[/url] .
prognozi na sport_ikPa
3 Oct 25 at 10:56 am
Great post. I was checking constantly this weblog and I am
impressed! Very helpful info specifically read the full release last part 🙂 I deal with such info a lot.
I was seeking this certain info for a very lengthy time.
Thank you and good luck.
read the full release
3 Oct 25 at 10:56 am
Закладки тут – купить гашиш, мефедрон, альфа-РїРІРї
Jeromeliz
3 Oct 25 at 10:57 am
ставки на спорт прогнозы от профессионалов [url=https://www.prognozy-na-sport-12.ru]https://www.prognozy-na-sport-12.ru[/url] .
prognozi na sport_yxMn
3 Oct 25 at 10:58 am
Сотрудничество со СтройСинтез стало удачным решением. Заказывали дом в скандинавском стиле, и команда реализовала проект идеально. Дом получился просторный и стильный, с удобной планировкой и большими окнами. Очень довольны результатом https://stroysyntez.com/
Brianvop
3 Oct 25 at 10:58 am
СтройСинтез построил для нас кирпичный дом с просторной мансардой. Работы были выполнены на высоком уровне, а качество материалов приятно удивило. Теперь у нас уютный и красивый дом. Все подробности можно посмотреть по ссылке: https://stroysyntez.com/
Brianvop
3 Oct 25 at 10:59 am
My results on the Availability Heuristic Test proved I rely too much on recent, vivid memories when making decisions. Wondering if you’ve checked Product Launches for more on this?
Product Launches
3 Oct 25 at 10:59 am
новости олимпиады [url=https://novosti-sporta-17.ru/]https://novosti-sporta-17.ru/[/url] .
novosti sporta_ofOi
3 Oct 25 at 11:00 am
Heard about Minotaurus ICO through a referral, and wow, the rewards are real. Battling obstacles in the game while staking $MTAUR for bonuses? Sign me up. This project’s momentum is unstoppable.
minotaurus token
WilliamPargy
3 Oct 25 at 11:00 am
Franks Farm играть в риобет
Andreasvek
3 Oct 25 at 11:02 am
новости легкой атлетики [url=http://novosti-sporta-15.ru/]http://novosti-sporta-15.ru/[/url] .
novosti sporta_ppma
3 Oct 25 at 11:02 am
Советую https://fedhill.org/vacancies/1009-charles-baltimore-md-21230/
PedroMop
3 Oct 25 at 11:03 am
бесплатные прогнозы на ставки [url=https://prognozy-na-sport-12.ru/]бесплатные прогнозы на ставки[/url] .
prognozi na sport_akMn
3 Oct 25 at 11:03 am
купить диплом железнодорожника [url=http://rudik-diplom8.ru/]купить диплом железнодорожника[/url] .
Diplomi_ykMt
3 Oct 25 at 11:04 am
https://www.wildberries.ru/catalog/514992745/detail.aspx
Kevinsaush
3 Oct 25 at 11:04 am
Когда обратился за продвижением, сайт практически не приносил заявок. После оптимизации и наращивания ссылочной массы ситуация изменилась. Сейчас трафик стабильный и есть постоянный поток заказов: https://mihaylov.digital/
Steventob
3 Oct 25 at 11:04 am
https://tadalmedspharmacy.shop/# tadalafil
Anthonynounk
3 Oct 25 at 11:05 am
Buy sildenafil: Sildenafil 100mg price – Buy sildenafil
BruceMaivy
3 Oct 25 at 11:05 am
купить диплом с занесением в реестр оренбург [url=www.frei-diplom4.ru]купить диплом с занесением в реестр оренбург[/url] .
Diplomi_dvOl
3 Oct 25 at 11:05 am
stavki prognozy [url=www.novosti-sporta-17.ru]www.novosti-sporta-17.ru[/url] .
novosti sporta_haOi
3 Oct 25 at 11:06 am
точные прогнозы на спорт от профессионалов [url=www.prognozy-na-sport-12.ru/]www.prognozy-na-sport-12.ru/[/url] .
prognozi na sport_iaMn
3 Oct 25 at 11:07 am
спортпрогноз на сегодня бесплатно [url=http://www.prognozy-na-sport-11.ru]спортпрогноз на сегодня бесплатно[/url] .
prognozi na sport_zmPa
3 Oct 25 at 11:07 am
купить диплом мастера маникюра и педикюра [url=http://rudik-diplom11.ru/]купить диплом мастера маникюра и педикюра[/url] .
Diplomi_xkMi
3 Oct 25 at 11:10 am
купить диплом в ачинске [url=https://rudik-diplom14.ru/]купить диплом в ачинске[/url] .
Diplomi_mgea
3 Oct 25 at 11:12 am
I think this is one of the most important info for me.
And i’m glad reading your article. But should remark on few general things, The site
style is ideal, the articles is really great : D.
Good job, cheers
online casino ohne limit
3 Oct 25 at 11:15 am
Very good post. I am facing many of these issues as well..
My site :: JAKKOUTTHEBXX’S All-Over Print Artful Coasters | Sold At Artsulli and Now on Amazon | You can’t spell Artsulli without Art!
JAKKOUTTHEBXX'S All-Over Print Artful Coasters | Sold At Artsulli and Now on Amazon | You can't spell Artsulli without Art!
3 Oct 25 at 11:16 am
Эта обзорная заметка содержит ключевые моменты и факты по актуальным вопросам. Она поможет читателям быстро ориентироваться в теме и узнать о самых важных аспектах сегодня. Получите краткий курс по современной информации и оставайтесь в курсе событий!
Не упусти важное! – https://by-womens.ru/stati/kakie-metody-zashchity-cvetushchih-derevev-ot-zamorozkov-naibolee-effektivny
NathanTox
3 Oct 25 at 11:16 am
It’s a pity you don’t have a donate button! I’d certainly
donate to this superb blog! I suppose for now i’ll settle for book-marking and adding your RSS feed to my Google account.
I look forward to brand new updates and will talk about this website with
my Facebook group. Talk soon!
Sérénor Paylix
3 Oct 25 at 11:17 am
прогнозы на спорт бесплатно на сегодня [url=www.prognozy-na-sport-11.ru]прогнозы на спорт бесплатно на сегодня[/url] .
prognozi na sport_iuPa
3 Oct 25 at 11:17 am
Лицензия Кюрасао, по которой работает оператор,
точно не определяет процесс верификации.
джойказино зеркало
3 Oct 25 at 11:19 am
точные бесплатные прогнозы на спорт [url=http://prognozy-na-sport-11.ru]точные бесплатные прогнозы на спорт[/url] .
prognozi na sport_wiPa
3 Oct 25 at 11:23 am
Магазин 24/7 – купить закладку MEF GASH SHIHSKI
Jeromeliz
3 Oct 25 at 11:23 am
куплю диплом кандидата наук [url=http://rudik-diplom5.ru]куплю диплом кандидата наук[/url] .
Diplomi_erma
3 Oct 25 at 11:24 am
купить диплом в мытищах [url=http://www.rudik-diplom14.ru]купить диплом в мытищах[/url] .
Diplomi_sbea
3 Oct 25 at 11:24 am
новости спорта россии [url=https://www.novosti-sporta-15.ru]https://www.novosti-sporta-15.ru[/url] .
novosti sporta_vbma
3 Oct 25 at 11:25 am
купить диплом воспитателя [url=www.rudik-diplom15.ru]купить диплом воспитателя[/url] .
Diplomi_ryPi
3 Oct 25 at 11:25 am
спортивные новости сегодня [url=http://novosti-sporta-17.ru/]http://novosti-sporta-17.ru/[/url] .
novosti sporta_fsOi
3 Oct 25 at 11:27 am