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!
Многие пользователи ежедневно пытаются найти единственно верный путь для доступа на торговую площадку Kraken, сталкиваясь с обилием мошеннических сайтов и неактуальной информацией. Чтобы минимизировать эти риски и сэкономить ваше время, существует надежное и централизованное решение. [url=https://kradark.net]кракен офиц сайт[/url] Данный сайт выступает в качестве постоянно обновляемого агрегатора рабочих зеркал, позволяя любому желающему 24/7 найти рабочий вход на площадку Кракен. Сохранив эту страницу, вы раз и навсегда решите проблему от необходимости выискивать рабочие ссылки на сомнительных форумах, рискуя собственными данными.
Othex
23 Oct 25 at 9:29 pm
1xbet g?ncel adres [url=https://1xbet-giris-2.com]https://1xbet-giris-2.com[/url] .
1xbet giris_glPt
23 Oct 25 at 9:31 pm
http://lenotoplenie.ru лучшие предложения для новых игроков и постоянных пользователей
CollinDwets
23 Oct 25 at 9:31 pm
1win это [url=https://www.1win5519.ru]1win это[/url]
1win_kg_uzEr
23 Oct 25 at 9:32 pm
Je suis emerveille par BassBet Casino, on ressent une ambiance de bar. Le catalogue est riche et varie, offrant des sessions live immersives. Avec des depots instantanes. Le support client est melodieux, joignable a toute heure. Les retraits sont fluides comme un solo, de temps a autre des bonus plus varies seraient un riff. Pour conclure, BassBet Casino vaut une jam session pour les joueurs en quete d’excitation ! De plus la navigation est simple et rythmee, amplifie le plaisir de jouer. Un autre atout les paiements securises en crypto, assure des transactions fiables.
https://bassbetcasinologinfr.com/|
DeltaBassC6zef
23 Oct 25 at 9:33 pm
bahis sitesi 1xbet [url=https://1xbet-giris-1.com]https://1xbet-giris-1.com[/url] .
1xbet giris_cxkt
23 Oct 25 at 9:33 pm
kraken онлайн
кракен android
JamesDaync
23 Oct 25 at 9:34 pm
Hello it’s me, I am also visiting this site on a regular basis, this web
site is in fact nice and the users are truly sharing good thoughts.
casino vovan
23 Oct 25 at 9:34 pm
купить медицинский диплом медсестры [url=http://www.frei-diplom14.ru]купить медицинский диплом медсестры[/url] .
Diplomi_hvoi
23 Oct 25 at 9:34 pm
кракен даркнет
kraken market
JamesDaync
23 Oct 25 at 9:35 pm
1xbet resmi sitesi [url=https://www.1xbet-giris-5.com]https://www.1xbet-giris-5.com[/url] .
1xbet giris_jhSa
23 Oct 25 at 9:37 pm
https://kannadamasti.cc/1xbet-promo-code-india-welcome-bonus-100/
lriofzk
23 Oct 25 at 9:38 pm
Tego typu podejrzana aplikacja wydaje sie byc oprogramowaniem do pobierania filmow online,
jednakze wielu uzytkownikow zgodnie twierdzi ze program w
ogole nie dziala.
savefrom net
23 Oct 25 at 9:38 pm
1xBet фрибет возможность сделать бесплатную ставку без риска для своего баланса
CollinDwets
23 Oct 25 at 9:39 pm
was sind buchmacher
My page – live Sportwetten
live Sportwetten
23 Oct 25 at 9:39 pm
кракен Москва
kraken vk6
kraken vk5
23 Oct 25 at 9:40 pm
1xbet ?ye ol [url=https://www.1xbet-giris-5.com]https://www.1xbet-giris-5.com[/url] .
1xbet giris_pbSa
23 Oct 25 at 9:41 pm
лучшие seo компании [url=http://reiting-seo-kompaniy.ru/]http://reiting-seo-kompaniy.ru/[/url] .
reiting seo kompanii_enon
23 Oct 25 at 9:41 pm
seo ranking services [url=https://reiting-seo-kompaniy.ru]https://reiting-seo-kompaniy.ru[/url] .
reiting seo kompanii_uhon
23 Oct 25 at 9:43 pm
bahis sitesi 1xbet [url=http://1xbet-giris-2.com]http://1xbet-giris-2.com[/url] .
1xbet giris_gtPt
23 Oct 25 at 9:44 pm
кракен vk2
kraken ссылка
JamesDaync
23 Oct 25 at 9:44 pm
I think what you said made a bunch of sense. But, think about
this, suppose you added a little content? I am not suggesting your content is not good,
but what if you added a headline that makes people desire
more? I mean PHP hook, building hooks in your application – Sjoerd
Maessen blog at Sjoerd Maessen blog is kinda
vanilla. You should look at Yahoo’s front page and note how they create post titles
to grab people interested. You might add a related video or a related pic or
two to get readers interested about what you’ve got to say.
In my opinion, it would bring your posts a little bit
more interesting.
TX88
23 Oct 25 at 9:45 pm
Hmm it looks like your website ate my first comment (it was
super long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly
enjoying your blog. I too am an aspiring blog writer but I’m still new to the whole
thing. Do you have any points for novice blog writers? I’d really appreciate it.
casinox güncel giriş
23 Oct 25 at 9:46 pm
https://farhankhatri663.gamerlaunch.com//forums/viewtopic.php?p=40634980&gid=607465#40634980
Marcosonese
23 Oct 25 at 9:46 pm
1xbetgiri? [url=1xbet-giris-4.com]1xbet-giris-4.com[/url] .
1xbet giris_urSa
23 Oct 25 at 9:46 pm
1xbet lite [url=https://1xbet-giris-7.com/]1xbet-giris-7.com[/url] .
1xbet giris_zoKn
23 Oct 25 at 9:47 pm
1ыин [url=https://1win5519.ru]1ыин[/url]
1win_kg_fnEr
23 Oct 25 at 9:47 pm
1xbet tr giri? [url=https://1xbet-giris-4.com]https://1xbet-giris-4.com[/url] .
1xbet giris_vkSa
23 Oct 25 at 9:49 pm
Мы не используем «универсальные коктейли». Капельницы собираются из модулей под ведущую задачу, а поведенческая часть усиливает эффект. Окончательные назначения делает врач с учётом противопоказаний и взаимодействий; таблица ниже — ориентир для пациента и семьи.
Разобраться лучше – [url=https://vyvod-iz-zapoya-murmansk15.ru/]вывод из запоя недорого в мурманске[/url]
Darwingow
23 Oct 25 at 9:49 pm
kraken
Also visit my homepage – https://xn--kr41-rzb.com
кракен 2025
23 Oct 25 at 9:50 pm
1xbwt giri? [url=http://1xbet-giris-5.com]http://1xbet-giris-5.com[/url] .
1xbet giris_usSa
23 Oct 25 at 9:52 pm
купить диплом в новокузнецке [url=http://rudik-diplom9.ru]купить диплом в новокузнецке[/url] .
Diplomi_ynei
23 Oct 25 at 9:52 pm
купить диплом в пскове [url=https://rudik-diplom6.ru/]купить диплом в пскове[/url] .
Diplomi_zvKr
23 Oct 25 at 9:54 pm
1вин бк [url=https://www.1win5519.ru]https://www.1win5519.ru[/url]
1win_kg_elEr
23 Oct 25 at 9:54 pm
1xbet tr [url=https://1xbet-giris-6.com/]1xbet tr[/url] .
1xbet giris_vhsl
23 Oct 25 at 9:55 pm
kraken tor
кракен онион
kraken marketplace
23 Oct 25 at 9:55 pm
kraken vpn
kraken vk5
кракен обмен
23 Oct 25 at 9:56 pm
seo agencies ranking [url=http://reiting-seo-kompaniy.ru]seo agencies ranking[/url] .
reiting seo kompanii_lcon
23 Oct 25 at 9:57 pm
1xbet giri? linki [url=https://1xbet-giris-6.com/]1xbet giri? linki[/url] .
1xbet giris_qgsl
23 Oct 25 at 9:58 pm
J-center Studio — школа, где учат профессии парикмахера на практике с четвёртого дня: работа с клиентами, колористика, мужские и женские стрижки, укладки, стажировка в салонах. Прозрачные цены, маленькие группы, инструменты и материалы — за счёт школы. Записаться и узнать ближайший старт можно на https://j-center.ru/ — расписание, форматы (группы, индивидуально, экстерн) и контакты на странице. Диплом и реальный опыт дают выпускникам быстрый вход в индустрию красоты.
cipymeRed
23 Oct 25 at 9:58 pm
one win token [url=http://1win5518.ru/]http://1win5518.ru/[/url]
1win_kg_ewkl
23 Oct 25 at 9:59 pm
1xbet [url=1xbet-giris-4.com]1xbet[/url] .
1xbet giris_mjSa
23 Oct 25 at 9:59 pm
If you would like to get a great deal from this article then you have to apply these techniques to your won weblog.
https://uk88top1.com/
23 Oct 25 at 10:00 pm
1win ios [url=http://1win5518.ru]1win ios[/url]
1win_kg_iwkl
23 Oct 25 at 10:01 pm
Сразу после поступления вызова специалист прибывает на дом для проведения первичного осмотра. На данном этапе нарколог:
Ознакомиться с деталями – [url=https://narcolog-na-dom-ryazan00.ru/]вызов нарколога на дом в рязани[/url]
FrankSwils
23 Oct 25 at 10:01 pm
1x giri? [url=http://1xbet-giris-4.com]http://1xbet-giris-4.com[/url] .
1xbet giris_osSa
23 Oct 25 at 10:05 pm
кракен ios
kraken market
kraken vk6
23 Oct 25 at 10:05 pm
купить диплом сварщика [url=www.rudik-diplom9.ru/]купить диплом сварщика[/url] .
Diplomi_tdei
23 Oct 25 at 10:05 pm
1xbet g?ncel adres [url=https://www.1xbet-giris-1.com]https://www.1xbet-giris-1.com[/url] .
1xbet giris_bvkt
23 Oct 25 at 10:06 pm
Для получения дополнительных бонусов от сервиса ставок 1xBet, следует соблюсти ряд правил, однако промокоды позволяют упростить процесс.Размеры бонусов, доступных новым клиентам через промокоды 1xBet, не всегда велики, но даже небольшой бонус способен существенно повысить ставочный баланс клиента.Активируйте промокод, чтобы получить бонус 100% на первый депозит в текущем 2026 году.Промокод можно найти по ссылке ниже — https://belygorod.ru/vote/pgs/?1xbet-promokod.html.
JesusJuize
23 Oct 25 at 10:07 pm