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!
Definitely imagine that which you stated. Your favourite justification seemed to be on the internet the simplest thing
to remember of. I say to you, I definitely get irked even as folks consider issues that
they just do not understand about. You managed to
hit the nail upon the top and also defined out
the whole thing with no need side-effects , other folks can take a signal.
Will likely be back to get more. Thanks
CorysWorld
29 Aug 25 at 11:49 pm
Приобрести кокаин, мефедрон, гашиш, бошки, альфа-пвп
DanielVeiff
29 Aug 25 at 11:51 pm
The discounted care sets enhance holidaynewsletters.com each other’s action as they are tailored to the skin’s needs, ensuring maximum results.
Bernardirrex
29 Aug 25 at 11:51 pm
застройщики частных домов иркутск [url=https://stroitelstvo-domov-irkutsk-1.ru/]https://stroitelstvo-domov-irkutsk-1.ru/[/url] .
stroitelstvo domov irkytsk_xvOr
29 Aug 25 at 11:52 pm
Very good write-up. I definitely appreciate this site. Stick with
it!
daily lung hygiene drops
29 Aug 25 at 11:54 pm
Beauty
Touche. Outstanding arguments. Keep up the great spirit.
Intimacy
29 Aug 25 at 11:56 pm
У нас https://sapphirecars.ru/ вы можете взять машину в аренду на сутки в Краснодаре без лишних формальностей. Наш автопрокат гарантирует ваше удовольствие от безупречного состояния и надежности наших дорогих автомобилей. Чтобы взять у нас автомобиль без водителя в аренду на день и более, вам понадобятся только паспорт РФ и водительские права.
Xywepgatly
29 Aug 25 at 11:59 pm
Каждый из наших врачей не только специалист, но и психолог, способный понять переживания пациента, создать атмосферу доверия. Мы применяем индивидуальный подход, позволяя каждому пациенту чувствовать себя комфортно. Наши наркологи проводят тщательную диагностику, разрабатывают планы лечения, основываясь на данных обследования, психологическом состоянии и других факторах. Основное внимание уделяется снижению абстиненции, лечению сопутствующих заболеваний, коррекции психоэмоционального состояния.
Выяснить больше – [url=https://alko-konsultaciya.ru/]наркологический вывод из запоя[/url]
Andrewwerie
30 Aug 25 at 12:00 am
диплом медсестры с занесением в реестр купить [url=http://www.arus-diplom35.ru]диплом медсестры с занесением в реестр купить[/url] .
Bistro i prosto zakazat diplom ob obrazovanii!_fyot
30 Aug 25 at 12:01 am
Hmm it looks like your site ate my first comment (it was super long) so I guess
I’ll just sum it up what I submitted and say, I’m thoroughly enjoying your blog.
I too am an aspiring blog blogger but I’m still new to
the whole thing. Do you have any tips and hints for rookie blog writers?
I’d genuinely appreciate it.
Local air duct installation near me
30 Aug 25 at 12:05 am
кашпо для цветов напольное [url=https://kashpo-napolnoe-moskva.ru/]кашпо для цветов напольное[/url] .
kashpo napolnoe _gvOi
30 Aug 25 at 12:05 am
Great site! I recommend it to everyone![url=https://cheater.fun/hacks_roblox]script roblox[/url]
CheaterFun1Nic
30 Aug 25 at 12:06 am
Hi! I could have sworn I’ve been to this blog before but after looking at many of the articles I realized
it’s new to me. Regardless, I’m certainly delighted I discovered it and I’ll be bookmarking
it and checking back often!
services
30 Aug 25 at 12:06 am
Современные методики
Разобраться лучше – http://vyvod-iz-zapoya-sochi7.ru/vyvod-iz-zapoya-na-domu-v-sochi/
JimmyOmify
30 Aug 25 at 12:06 am
https://auto-rescue.ru/
Georgebon
30 Aug 25 at 12:08 am
http://hotel-golebiewski.phorum.pl/viewtopic.php?p=618610#618610
http://hotel-golebiewski.phorum.pl/viewtopic.php?p=618610#618610
30 Aug 25 at 12:13 am
Приобрести кокаин, мефедрон, гашиш, бошки, альфа-пвп
DanielVeiff
30 Aug 25 at 12:14 am
Thanks very nice blog!
sarang777
30 Aug 25 at 12:17 am
купить дом под ключ [url=www.stroitelstvo-domov-irkutsk-1.ru/]www.stroitelstvo-domov-irkutsk-1.ru/[/url] .
stroitelstvo domov irkytsk_ecOr
30 Aug 25 at 12:20 am
Just wish to say your article is as astonishing. The clarity to your post is
simply nice and i could think you’re knowledgeable in this subject.
Well together with your permission let me to grab your RSS feed to keep updated with impending post.
Thank you a million and please carry on the enjoyable work.
Pusulabet
30 Aug 25 at 12:21 am
It should be taken into account that the best results in workingholiday365.com thermal insulation are achieved with a comprehensive approach, which includes not only the selection of high-quality materials, but also competent installation.
Jamesbiz
30 Aug 25 at 12:22 am
SEO-продвижение сайтов https://raskrutka-sajtov-bystro77.ru в Москве: вывод в ТОП поисковиков, рост трафика и заявок. Полный комплекс — аудит, семантика, оптимизация, ссылки. Эффективное продвижение под ключ.
raskrutka-sajtov-585
30 Aug 25 at 12:22 am
1wbona: bonaslot link resmi mudah diakses – 1wbona
LouisJoync
30 Aug 25 at 12:24 am
Hi would you mind sharing which blog platform you’re using?
I’m looking to start my own blog soon but I’m
having a difficult time deciding between BlogEngine/Wordpress/B2evolution and Drupal.
The reason I ask is because your design and style seems different
then most blogs and I’m looking for something unique.
P.S My apologies for being off-topic but I had to ask!
Лицензированное казино с выводом
30 Aug 25 at 12:28 am
наркологический частный центр [url=narkologicheskaya-klinika-12.ru]narkologicheskaya-klinika-12.ru[/url] .
narkologicheskaya klinika_dyMn
30 Aug 25 at 12:28 am
At this time it appears like Expression Engine is the best blogging platform available right now.
(from what I’ve read) Is that what you’re using on your blog?
대전출장마사지
30 Aug 25 at 12:28 am
kraken darknet ссылка
RichardPep
30 Aug 25 at 12:29 am
SEO-продвижение сайтов https://raskrutka-sajtov-bystro77.ru в Москве: вывод в ТОП поисковиков, рост трафика и заявок. Полный комплекс — аудит, семантика, оптимизация, ссылки. Эффективное продвижение под ключ.
raskrutka-sajtov-463
30 Aug 25 at 12:29 am
построить дом в иркутске [url=http://www.stroitelstvo-domov-irkutsk-1.ru]http://www.stroitelstvo-domov-irkutsk-1.ru[/url] .
stroitelstvo domov irkytsk_xoOr
30 Aug 25 at 12:31 am
Мы изготавливаем дипломы любой профессии по приятным тарифам. Покупка диплома, который подтверждает обучение в ВУЗе, – это выгодное решение. Заказать диплом о высшем образовании: [url=http://beeasy.vn/read-blog/27735_kupit-diplom-ob-obrazovanii.html/]beeasy.vn/read-blog/27735_kupit-diplom-ob-obrazovanii.html[/url]
Mazrhwg
30 Aug 25 at 12:32 am
Этот формат позволяет пациентам получить профессиональную помощь в комфортной домашней обстановке. Такой подход не только обеспечивает удобство, но и гарантирует конфиденциальность, что особенно важно для многих людей.
Подробнее можно узнать тут – [url=https://narcolog-na-dom-v-krasnoyarske55.ru/]www.domen.ru[/url]
CurtisUsalk
30 Aug 25 at 12:34 am
Купить кокаин, мефедрон, гашиш, бошки, альфа-пвп
DanielVeiff
30 Aug 25 at 12:36 am
Incredible story there. What happened after? Good luck!
suppliers in Pakistan
30 Aug 25 at 12:38 am
[…] more of a spectrum than three distinct boxes, these categories provide a useful framework for casino understanding how a slot game […]
Online Casino vs. Brick-and-Mortar Casino: A Comparison – SIS INTEGRATION
30 Aug 25 at 12:38 am
Каждый день запоя увеличивает риск для жизни. Не рискуйте — специалисты в Самаре приедут на дом и окажут экстренную помощь. Без боли, стресса и ожидания.
Разобраться лучше – [url=https://vyvod-iz-zapoya-v-stacionare-samara16.ru/]вывод из запоя недорого самара[/url]
Pablotug
30 Aug 25 at 12:38 am
Its not my first time to pay a quick visit this web site, i am browsing this website
dailly and take nice information from here daily.
business blog
30 Aug 25 at 12:39 am
Thanks for sharing your thoughts about real money
online casinos. Regards
real money online casinos
30 Aug 25 at 12:39 am
I used to be recommended this web site via my cousin. I am no
longer positive whether or not this submit is written via him as
nobody else understand such designated approximately my difficulty.
You’re amazing! Thanks!
http://git.ybrsmfw.cn
30 Aug 25 at 12:40 am
4M Dental Implant Center Saan Diego
5643 Copley Ⅾr ste 210, San Diego,
СA 92111, United Ⴝtates
18582567711
oral surgery
oral surgery
30 Aug 25 at 12:40 am
Когда организм на пределе, важна срочная помощь в Самаре — это команда опытных наркологов, которые помогут быстро и мягко выйти из запоя без вреда для здоровья.
Получить дополнительную информацию – [url=https://vyvod-iz-zapoya-v-stacionare-samara15.ru/]наркология вывод из запоя[/url]
Michaelamoma
30 Aug 25 at 12:40 am
Каждый день запоя увеличивает риск для жизни. Не рискуйте — специалисты в Самаре приедут на дом и окажут экстренную помощь. Без боли, стресса и ожидания.
Получить больше информации – [url=https://vyvod-iz-zapoya-v-stacionare-samara14.ru/]вывод из запоя капельница[/url]
Michaelplert
30 Aug 25 at 12:40 am
Каждый день запоя увеличивает риск для жизни. Не рискуйте — специалисты в Самаре приедут на дом и окажут экстренную помощь. Без боли, стресса и ожидания.
Ознакомиться с деталями – [url=https://vyvod-iz-zapoya-v-stacionare-samara17.ru/]вывод из запоя цена[/url]
Justingof
30 Aug 25 at 12:40 am
F168 uy tín năm 2025, đa dạng game thú vị, bảo mật an toàn, ưu đãi khủng.
f 168
30 Aug 25 at 12:41 am
agen garuda888 bonus new member: garuda888 live casino Indonesia – 1win888indonesia
LouisJoync
30 Aug 25 at 12:45 am
If you desire to increase your know-how just keep
visiting this site and be updated with the hottest news posted
here.
Eternal Lunesta
30 Aug 25 at 12:48 am
купить диплом спб занесением реестр [url=https://arus-diplom33.ru/]купить диплом спб занесением реестр[/url] .
Priobresti diplom o visshem obrazovanii!_cuoi
30 Aug 25 at 12:50 am
отели анапы с бассейном все включено
ScottDow
30 Aug 25 at 12:50 am
bonaslot link resmi mudah diakses [url=https://1wbona.com/#]bonaslot link resmi mudah diakses[/url] 1wbona
Aaronreima
30 Aug 25 at 12:51 am
https://avtoinstruktor177.ru/
Georgebon
30 Aug 25 at 12:52 am
Flush Factor Plus seems like a really interesting supplement for supporting gut health and detox.
I like that it’s focused on cleansing the digestive system while also helping with energy
and overall wellness. If you’re looking for a natural
way to reset your body and feel lighter, Flush
Factor Plus looks like a great option
Flush Factor Plus
30 Aug 25 at 12:54 am