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!
MexiCare Rx Hub: mexican drugstore online – mexican border pharmacies shipping to usa
Richardquaxy
31 Jul 25 at 6:08 am
https://canadrxnexus.com/# safe canadian pharmacy
Jessegap
31 Jul 25 at 6:10 am
обучение кайтсёрфингу Кайт школа: ваш путь к мастерству. Профессиональные инструкторы, безопасное обучение и индивидуальный подход. Станьте уверенным кайтсёрфером!
Kennethvut
31 Jul 25 at 6:12 am
Wow, this article is good, my sister is analyzing these things,
thus I am going to tell her.
viagra
31 Jul 25 at 6:12 am
кайт школа “Почувствуй ветер”: Как выбрать кайт под свой уровень и стиль, чтобы не облажаться на споте
Kennethvut
31 Jul 25 at 6:13 am
кайт Кайтсёрфинг и здоровье: спорт для души и тела. Улучшите свою физическую форму и получите заряд энергии.
Kennethvut
31 Jul 25 at 6:14 am
В Коломне Частный Медик?24: стационарная капельница от запоя с медицинским сопровождением — переходите на страницу.
Узнать больше – [url=https://kapelnica-ot-zapoya-kolomna16.ru/]врач на дом капельница от запоя в коломне[/url]
AlbertEsold
31 Jul 25 at 6:15 am
Чем дольше и интенсивнее продолжается запой, тем выше становится риск возникновения широкого спектра серьезных и потенциально смертельных осложнений, начиная от тяжелых нарушений работы сердечно-сосудистой системы и заканчивая необратимым повреждением жизненно важных внутренних органов, что требует немедленной и комплексной медицинской помощи
Подробнее можно узнать тут – [url=https://vyvod-iz-zapoya-arkhangelsk66.ru/]вывод из запоя дешево архангельск[/url]
TamikaNounc
31 Jul 25 at 6:15 am
Heya i’m for the first time here. I found this board and I to find It
really helpful & it helped me out a lot. I am hoping to present something back and aid others such as you
aided me.
Have a look at my website … Hungarian KPN alternative
Hungarian KPN alternative
31 Jul 25 at 6:17 am
В Коломне Частный Медик?24: стационарная капельница от запоя с медицинским сопровождением — переходите на страницу.
Выяснить больше – [url=https://kapelnica-ot-zapoya-kolomna14.ru/]vyzvat-kapelniczu-ot-zapoya kolomna[/url]
HenryFem
31 Jul 25 at 6:17 am
После звонка специалист клиники «ВитаЛайн» оперативно отправляется по указанному адресу и обычно прибывает в течение 30–60 минут. На месте врач сразу проводит детальную диагностику, оценивая состояние пациента: проверяет пульс, давление, сатурацию, степень интоксикации и наличие хронических болезней. На основании результатов осмотра нарколог разрабатывает индивидуальную схему терапии.
Углубиться в тему – [url=https://narcolog-na-dom-novosibirsk0.ru/]вызов нарколога на дом в новосибирске[/url]
Jameshit
31 Jul 25 at 6:18 am
Для проживающих в Балашихе: услуга стационарного вывода из запоя от Частного Медика 24 — переходите по ссылке.
Интересует подробная информация – [url=https://vyvod-iz-zapoya-v-stacionare-balashiha11.ru/]вывод из запоя недорого город балашиха[/url]
RichardBut
31 Jul 25 at 6:22 am
кайт Обучение кайтсёрфингу: от первых шагов до виртуозных трюков. Поэтапное обучение, начиная с основ управления кайтом на берегу и заканчивая сложными прыжками и вращениями в воде.
Kennethvut
31 Jul 25 at 6:23 am
canadian pharmacy 24: CanadRx Nexus – CanadRx Nexus
Samuelarori
31 Jul 25 at 6:24 am
Undeniably imagine that which you said. Your favorite justification seemed to be on the internet the simplest
thing to take note of. I say to you, I certainly get annoyed even as other
folks think about concerns that they just don’t recognize about.
You managed to hit the nail upon the highest as neatly as
outlined out the entire thing without having side effect , people can take a signal.
Will probably be again to get more. Thanks
v9bet
31 Jul 25 at 6:24 am
reputable indian pharmacies [url=https://indigenixpharm.shop/#]IndiGenix Pharmacy[/url] top 10 pharmacies in india
JamesCoaby
31 Jul 25 at 6:24 am
кайт Кайтсёрфинг и здоровье: польза и противопоказания. Узнайте о пользе кайтсёрфинга для здоровья, а также о возможных противопоказаниях и мерах предосторожности.
Kennethvut
31 Jul 25 at 6:26 am
кайт школа Кайтинг: стиль жизни, полный драйва. Откройте для себя мир кайтинга, сообщество увлеченных людей и новые горизонты.
Kennethvut
31 Jul 25 at 6:27 am
Hi there everyone, it’s my first visit at this web site, and article is really fruitful designed for
me, keep up posting these articles or reviews.
سامانه جامع مالی حسابیار دانشگاه آزاد hesabyar.iau.ir
31 Jul 25 at 6:28 am
В Коломне Частный Медик?24: стационарная капельница от запоя с медицинским сопровождением — переходите на страницу.
Подробнее – [url=https://kapelnica-ot-zapoya-kolomna15.ru/]поставить капельницу от запоя[/url]
MatthewNouff
31 Jul 25 at 6:29 am
CanadRx Nexus: CanadRx Nexus – CanadRx Nexus
Samuelarori
31 Jul 25 at 6:30 am
Howdy I am so thrilled I found your webpage, I really found you by accident, while I was browsing on Aol for
something else, Nonetheless I am here now and would just like to say thanks for a fantastic post and a all round entertaining blog (I also love the theme/design), I don’t have
time to read through it all at the minute but I have bookmarked
it and also included your RSS feeds, so when I have time I will be back to read more,
Please do keep up the awesome job.
رشته روانشناسی بدون کنکور
31 Jul 25 at 6:39 am
Стационарный вывод из запоя в Балашихе — лечение в Частном Медике 24, переходите по ссылке на страницу услуги.
Изучить материалы по теме – [url=https://vyvod-iz-zapoya-v-stacionare-balashiha12.ru/]balashiha[/url]
ElbertCox
31 Jul 25 at 6:41 am
I’ve read a few good stuff here. Definitely
price bookmarking for revisiting. I surprise how so much attempt you place to create this
sort of excellent informative web site.
رشته صنایع غذایی بدون کنکور
31 Jul 25 at 6:46 am
Первый этап лечения направлен на быстрый вывод токсинов, накопившихся в организме вследствие длительного употребления алкоголя. Для этого применяются современные препараты, позволяющие очистить кровь и восстановить нормальный обмен веществ.
Ознакомиться с деталями – http://vyvod-iz-zapoya-krasnoyarsk66.ru/vyvod-iz-zapoya-na-domu-krasnoyarsk/https://vyvod-iz-zapoya-krasnoyarsk66.ru
MichaelViamb
31 Jul 25 at 6:49 am
reputable indian online pharmacy: IndiGenix Pharmacy – IndiGenix Pharmacy
Samuelarori
31 Jul 25 at 6:54 am
Получить диплом ВУЗа поможем. Купить диплом в Чебоксарах – [url=http://diplomybox.com/kupit-diplom-cheboksary/]diplomybox.com/kupit-diplom-cheboksary[/url]
Cazrdwr
31 Jul 25 at 7:00 am
Hey I am so delighted I found your weblog, I really found you by mistake, while
I was browsing on Google for something else, Nonetheless
I am here now and would just like to say cheers for a remarkable post and a all round interesting blog
(I also love the theme/design), I don’t have time to
look over it all at the moment but I have saved it and also
added in your RSS feeds, so when I have time I will be back to read
much more, Please do keep up the awesome b.
نتایج نقل و انتقالات برون استانی ۱۴۰۴
31 Jul 25 at 7:03 am
I’m amazed, I have to admit. Seldom do I come across a blog that’s equally educative and engaging, and without
a doubt, you have hit the nail on the head. The problem is an issue that not enough folks are speaking intelligently about.
I am very happy I found this in my search for something relating to
this.
หมุนวงล้อ
31 Jul 25 at 7:08 am
После поступления вызова наш нарколог выезжает к пациенту в кратчайшие сроки, прибывая по адресу в пределах 30–60 минут. Специалист начинает процедуру с подробного осмотра и диагностики, измеряя ключевые показатели организма: артериальное давление, частоту пульса, насыщенность кислородом и собирая подробный анамнез.
Подробнее – http://narcolog-na-dom-novosibirsk00.ru/narkolog-na-dom-czena-novosibirsk/
DanielHah
31 Jul 25 at 7:10 am
Thanks for finally talking about > PHP hook, building hooks in your application – Sjoerd Maessen blog at Sjoerd Maessen blog < Loved it!
for more information
31 Jul 25 at 7:15 am
купить диплом с проведением в [url=www.arus-diplom32.ru/]купить диплом с проведением в[/url] .
Diplomi_djpi
31 Jul 25 at 7:15 am
I couldn’t refrain from commenting. Perfectly written!
Look into my homepage :: internet in Hongarije
internet in Hongarije
31 Jul 25 at 7:18 am
купить автомобиль в корее с доставкой [url=http://www.avto-iz-korei-1.ru]купить автомобиль в корее с доставкой[/url] .
Avto iz Korei_kfPi
31 Jul 25 at 7:21 am
online shopping pharmacy india [url=https://indigenixpharm.com/#]IndiGenix Pharmacy[/url] cheapest online pharmacy india
JamesCoaby
31 Jul 25 at 7:21 am
Hi! I know this is kinda off topic but I was wondering which
blog platform are you using for this site? I’m getting sick
and tired of WordPress because I’ve had problems with hackers and I’m looking at alternatives for another platform.
I would be great if you could point me in the direction of a good platform.
best online slots
31 Jul 25 at 7:22 am
купить диплом медсестры с занесением в реестр [url=http://arus-diplom31.ru/]купить диплом медсестры с занесением в реестр[/url] .
Diplomi_brpl
31 Jul 25 at 7:31 am
привезти автомобиль из южной кореи [url=http://www.avto-iz-korei-1.ru]привезти автомобиль из южной кореи[/url] .
Avto iz Korei_ghPi
31 Jul 25 at 7:32 am
download comics read comics online free
batcave-833
31 Jul 25 at 7:38 am
фирмы по привозу авто из кореи [url=www.avto-iz-korei-1.ru/]www.avto-iz-korei-1.ru/[/url] .
Avto iz Korei_ncPi
31 Jul 25 at 7:38 am
Hello there! I could have sworn I’ve been to this blog before but after checking through some
of the post I realized it’s new to me. Nonetheless,
I’m definitely happy I found it and I’ll be bookmarking and checking back frequently!
ثبت نام حضوری دانشگاه پیام نور
31 Jul 25 at 7:40 am
авиатор игра на деньги 1win [url=1win1140.ru]1win1140.ru[/url]
1win_wdMi
31 Jul 25 at 7:45 am
india online pharmacy: IndiGenix Pharmacy – IndiGenix Pharmacy
Richardquaxy
31 Jul 25 at 7:48 am
english manga online free read shonen manga free
manga-166
31 Jul 25 at 7:51 am
Алкогольный запой — это не просто последствие длительного употребления спиртного, а состояние, которое может привести к необратимым последствиям без своевременного медицинского вмешательства. Длительная интоксикация вызывает нарушения в работе печени, сердца, почек, приводит к обезвоживанию, сбою электролитного баланса, а также провоцирует серьёзные психоэмоциональные изменения. Самостоятельный отказ от алкоголя может стать причиной опасных осложнений: судорог, гипертонических кризов, панических атак и даже алкогольного психоза.
Углубиться в тему – http://vyvod-iz-zapoya-arkhangelsk6.ru/vyvod-iz-zapoya-klinika-arkhangelsk/
CharlesRam
31 Jul 25 at 7:52 am
диплом о среднем образовании купить легально [url=https://www.arus-diplom31.ru]https://www.arus-diplom31.ru[/url] .
Diplomi_iqpl
31 Jul 25 at 7:53 am
When I originally commented I seem to have clicked on the -Notify me when new comments are added-
checkbox and from now on every time a comment is
added I recieve 4 emails with the exact same comment.
There has to be a means you can remove me from that
service? Thanks!
bongdaluclub
31 Jul 25 at 7:53 am
подбор и доставка авто из кореи [url=https://avto-iz-korei-1.ru/]подбор и доставка авто из кореи[/url] .
Avto iz Korei_wyPi
31 Jul 25 at 7:53 am
манхва онлайн топ манхвы
com-x-246
31 Jul 25 at 8:00 am
MexiCare Rx Hub: legit mexican pharmacy without prescription – best prices on finasteride in mexico
Richardbog
31 Jul 25 at 8:02 am