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!
1xbet ?ye ol [url=https://1xbet-giris-8.com]https://1xbet-giris-8.com[/url] .
1xbet giris_epPn
24 Oct 25 at 11:49 am
1xbet guncel [url=http://1xbet-giris-10.com]1xbet guncel[/url] .
1xbet giris_suka
24 Oct 25 at 11:49 am
online casino united states that accept paysafe, uptown pokies no deposit bonus 2021 united states and buy pokie machine usa, or free casino money united states
Also visit my site: all gambling in kenya; Tawanna,
Tawanna
24 Oct 25 at 11:49 am
Основная задача стационарного лечения — не просто вывести человека из кризисного состояния, а вернуть ясность мышления и устойчивость физиологических функций. Поэтому врачи клиники используют современные методы детоксикации, витаминотерапии, ноотропные препараты, психотерапевтические практики короткого действия и физиотерапевтические модули, направленные на восстановление сна, памяти и концентрации.
Ознакомиться с деталями – http://narkologicheskaya-klinika-stavropol0.ru/narkolog-psikholog-stavropol/
Justinvodia
24 Oct 25 at 11:51 am
1xbet turkiye [url=https://1xbet-9.com/]1xbet-9.com[/url] .
1xbet_yzSn
24 Oct 25 at 11:52 am
1xbet g?ncel [url=https://1xbet-giris-3.com]1xbet g?ncel[/url] .
1xbet giris_biMi
24 Oct 25 at 11:53 am
1 xbet [url=1xbet-giris-7.com]1 xbet[/url] .
1xbet giris_psKn
24 Oct 25 at 11:54 am
Operating seamlessly across traditional finance and the digital asset world has always been a logistical nightmare for
many in the GSA community. The endless delays and opaque processes between fiat and crypto platforms can severely slow down vital
transactions. This is precisely why the Paybis fintech platform is so compelling.
They aren’t just another crypto exchange; they’ve built a remarkably fluid gateway
that masterfully consolidates both fiat and cryptocurrency
banking. Imagine managing treasury across USD, EUR, and a vast selection of major digital assets—all from a streamlined platform.
Their focus on regulatory compliance means you can transact with confidence.
A brief comment can’t possibly do justice to the full scope of
their capabilities, especially their advanced tools for
institutional clients. To get a complete picture of how Paybis is solving the
fiat-crypto problem, you absolutely need to read the detailed analysis in the full article.
It breaks down their KYC process, supported regions, and API integration in a way that is incredibly insightful.
Don’t just take my word for it check out the
piece to see if their platform aligns with your
strategic financial goals. It’s a comprehensive overview for anyone in our field looking to leverage
modern fintech. The link is in the main post—you won’t regret
it.
article
24 Oct 25 at 11:54 am
diskret leverans i Sverige [url=http://mannensapotek.com/#]köp receptfria potensmedel online[/url] diskret leverans i Sverige
Davidduese
24 Oct 25 at 11:55 am
Терапия в клинике строится на системном подходе, позволяющем постепенно восстанавливать здоровье и формировать новые жизненные установки.
Узнать больше – http://narcologicheskaya-klinika-perm0.ru/perm-narkologiya/
StevenThalt
24 Oct 25 at 11:57 am
birxbet giri? [url=http://1xbet-7.com/]http://1xbet-7.com/[/url] .
1xbet_mwol
24 Oct 25 at 11:57 am
Инфузионная терапия в «ТагилМед Реал» — это точный инструмент под конкретный запрос: обезвоживание, вегетативная нестабильность, нарушения сна, «утренний туман». Состав и дозировки подбирает врач с учётом возраста, коморбидности и лекарственных взаимодействий. Важно понимать: больше компонентов не значит лучше; главная ценность — фокус и безопасность.
Узнать больше – http://narkologicheskaya-klinika-nizhnij-tagil0.ru/
Bryanler
24 Oct 25 at 11:58 am
купить диплом в махачкале [url=http://www.rudik-diplom14.ru]купить диплом в махачкале[/url] .
Diplomi_dbea
24 Oct 25 at 11:58 am
В клинике применяются комплексные программы, охватывающие все стадии терапии. Такой подход позволяет обеспечить пациенту полный спектр помощи — от первой консультации до социальной адаптации.
Разобраться лучше – [url=https://narcologicheskaya-klinika-omsk0.ru/]платная наркологическая клиника[/url]
Michaelmoire
24 Oct 25 at 11:58 am
Если дома действительно шумно (ремонт, маленькие дети, вечерние гости) или состояние нестабильно, предложим короткое наблюдение в клинике: отдельный вход, «тихий коридор», камерные посты, затем — возвращение домой и продолжение амбулаторного маршрута. Важен не формат, а предсказуемый результат: степень облегчения должна соответствовать целям этапа, а не множеству случайных факторов среды.
Получить дополнительную информацию – [url=https://vyvod-iz-zapoya-nizhnij-tagil0.ru/]вывод из запоя недорого в нижнем тагиле[/url]
ClaudeTwilm
24 Oct 25 at 12:00 pm
купить диплом техникума легче [url=www.frei-diplom11.ru/]купить диплом техникума легче[/url] .
Diplomi_ctsa
24 Oct 25 at 12:00 pm
https://rosslestnica.ru/
Victorcrype
24 Oct 25 at 12:00 pm
1xbet mobil giri? [url=https://1xbet-giris-8.com]https://1xbet-giris-8.com[/url] .
1xbet giris_tnPn
24 Oct 25 at 12:00 pm
1xbet giri? [url=http://www.1xbet-giris-7.com]1xbet giri?[/url] .
1xbet giris_rzKn
24 Oct 25 at 12:00 pm
1xbwt giri? [url=https://www.1xbet-4.com]https://www.1xbet-4.com[/url] .
1xbet_liol
24 Oct 25 at 12:02 pm
1xbet giri? adresi [url=http://1xbet-giris-9.com]1xbet giri? adresi[/url] .
1xbet giris_hbon
24 Oct 25 at 12:02 pm
wettquoten europameister
Here is my blog handicap live wette (https://Www.Securifi.com)
https://Www.Securifi.com
24 Oct 25 at 12:03 pm
https://лестницы-в-москве.рф
TravisGaf
24 Oct 25 at 12:03 pm
https://www.vixio.com
ArnoldKam
24 Oct 25 at 12:05 pm
xbet giri? [url=http://1xbet-giris-10.com/]xbet giri?[/url] .
1xbet giris_qpka
24 Oct 25 at 12:06 pm
Капельницы в «СаратовМед Профи» — это конструктор из тщательно подобранных модулей. Каждый модуль решает одну задачу и имеет свой ожидаемый горизонт эффекта. Важно не название, а логика: задача > опора среды > как проверяем > когда ждём результат.
Подробнее тут – [url=https://vyvod-iz-zapoya-saratov0.ru/]www.domen.ru[/url]
DavidCag
24 Oct 25 at 12:06 pm
https://www.primopianomolise.it/
ArnoldKam
24 Oct 25 at 12:07 pm
1xbet giris [url=http://www.1xbet-giris-10.com]1xbet giris[/url] .
1xbet giris_kwka
24 Oct 25 at 12:08 pm
I have been browsing online more than 4 hours today, yet I never found any interesting
article like yours. It’s pretty worth enough for me.
Personally, if all web owners and bloggers made good content as you did, the web will be a lot
more useful than ever before.
Robux Murah
24 Oct 25 at 12:08 pm
1xbet giri?i [url=https://1xbet-9.com]https://1xbet-9.com[/url] .
1xbet_vqSn
24 Oct 25 at 12:09 pm
erectiepillen discreet bestellen [url=http://herengezondheid.com/#]officiële Sildenafil webshop[/url] Viagra online kopen Nederland
Davidduese
24 Oct 25 at 12:09 pm
comprar Sildenafilo sin receta: farmacia confiable en España – Confia Farmacia
Jesuskax
24 Oct 25 at 12:10 pm
https://bestforum.forum-top.ru/viewtopic.php?id=3741#p6494
RichardWet
24 Oct 25 at 12:11 pm
J’aime l’ambiance crypto de Monte Cryptos Casino, ca offre un plaisir numerique intense. Il y a une abondance de jeux envoutants, avec des slots aux themes futuristes. Boostant votre capital initial. Le support client est irreprochable, joignable a tout moment. Les paiements sont securises par blockchain, de temps a autre des offres plus genereuses ajouteraient du charme. Dans l’ensemble, Monte Cryptos Casino offre une experience inoubliable pour ceux qui parient avec des cryptos ! De plus la navigation est simple comme un wallet, ajoute une touche de sophistication. Un avantage notable les options de paris variees, garantit des transactions fiables.
Cliquer maintenant|
ShadowBitK4zef
24 Oct 25 at 12:11 pm
Je suis absolument envoute par Monte Cryptos Casino, on ressent une energie blockchain. Le catalogue est opulent et divers, proposant des tables sophistiquees. Boostant votre capital initial. Les agents repondent avec une vitesse fulgurante, avec une aide rapide et fiable. Les paiements sont securises par blockchain, de temps a autre des bonus plus varies seraient un atout. En resume, Monte Cryptos Casino est une plateforme qui domine l’univers crypto pour ceux qui parient avec des cryptos ! Ajoutons que le design est moderne et captivant, facilite une immersion totale. A souligner les paiements securises en BTC/ETH, garantit des transactions fiables.
Explorer le site web|
CodeVortexP6zef
24 Oct 25 at 12:11 pm
https://www.capetownexpress.com/newsr/15805
uveoeyw
24 Oct 25 at 12:11 pm
https://t.me/bs_1xbet/35
https://t.me/s/bs_1xbet/2
24 Oct 25 at 12:12 pm
https://t.me/bs_1xbet/50
https://t.me/bs_1xbet/7
24 Oct 25 at 12:13 pm
J’adore l’elegance de Impressario Casino, c’est une plateforme qui evoque le raffinement. La selection de jeux est somptueuse, offrant des sessions live sophistiquees. Le bonus de bienvenue est delicieux. Le suivi est irreprochable, joignable a toute heure. Le processus est simple et elegant, bien que plus de promos regulieres ajouteraient du piquant. Au final, Impressario Casino garantit un plaisir constant pour les passionnes de jeux modernes ! A noter la navigation est simple et gracieuse, facilite une immersion totale. Egalement appreciable les options de paris sportifs variees, offre des recompenses continues.
Lire les dГ©tails|
DijonDelightI9zef
24 Oct 25 at 12:13 pm
https://rosslestnica.ru/
Victorcrype
24 Oct 25 at 12:13 pm
1 x bet [url=http://www.1xbet-giris-10.com]1 x bet[/url] .
1xbet giris_epka
24 Oct 25 at 12:13 pm
1xbet yeni giri? [url=1xbet-4.com]1xbet-4.com[/url] .
1xbet_vrol
24 Oct 25 at 12:14 pm
1xbwt giri? [url=http://1xbet-giris-9.com]http://1xbet-giris-9.com[/url] .
1xbet giris_vnon
24 Oct 25 at 12:14 pm
xbet giri? [url=https://1xbet-giris-8.com/]xbet giri?[/url] .
1xbet giris_dhPn
24 Oct 25 at 12:16 pm
1xbet turkiye [url=www.1xbet-giris-7.com]www.1xbet-giris-7.com[/url] .
1xbet giris_vzKn
24 Oct 25 at 12:16 pm
I didn’t have the right size pan, but the Baking Pan Size Converter saved my brownie recipe!
Product Launches
24 Oct 25 at 12:17 pm
https://лестницы-в-москве.рф
TravisGaf
24 Oct 25 at 12:17 pm
1xbet g?ncel [url=https://1xbet-giris-10.com/]1xbet g?ncel[/url] .
1xbet giris_kska
24 Oct 25 at 12:17 pm
bahis siteler 1xbet [url=1xbet-giris-3.com]1xbet-giris-3.com[/url] .
1xbet giris_yvMi
24 Oct 25 at 12:18 pm
https://t.me/bs_1xbet/25
https://t.me/s/bs_1xbet/28
24 Oct 25 at 12:18 pm