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!
net seo [url=www.optimizaciya-i-seo-prodvizhenie-sajtov-moskva-1.ru/]www.optimizaciya-i-seo-prodvizhenie-sajtov-moskva-1.ru/[/url] .
optimizaciya i seo prodvijenie saitov moskva_bdPi
28 Oct 25 at 3:50 pm
Интернет объединяет поколения сайт kraken onion kraken маркетплейс зеркало кракен ссылка кракен даркнет
RichardPep
28 Oct 25 at 3:50 pm
Вывод из запоя — это не только про капельницу. Это управляемая цепочка решений, где сначала оцениваются риски (дыхание, сознание, обезвоживание), затем подбирается минимально достаточная инфузионная схема и психосоматическая поддержка, а после — формируется «окно наблюдения» на первую ночь. В наркологической клинике «ЧелМед Детокс» все этапы формализованы: врач фиксирует исходные показатели, назначает узкий модуль вмешательства и выключает его ровно в тот момент, когда цель достигнута. Такой подход избегает полипрагмазии, делает лечение предсказуемым и снимает тревогу у пациента и семьи: каждый понимает, что будет происходить в ближайшие часы, какие критерии успеха и когда наступит пересмотр тактики.
Подробнее можно узнать тут – [url=https://vyvod-iz-zapoya-v-chelyabinske16.ru/]вывод из запоя клиника челябинск[/url]
JerryCep
28 Oct 25 at 3:51 pm
кракен маркетплейс
kraken market
Henryamerb
28 Oct 25 at 3:51 pm
findjoytoday – I found a few items that might make good gifts—nice variety.
Buster Rydolph
28 Oct 25 at 3:51 pm
How to win in Calgary Lottery: Boost your chances by playing consistently, joining lottery pools, and choosing less popular combinations. Remember, winning requires luck and responsible play: how to win in Calgary lottery
GabrielLyday
28 Oct 25 at 3:52 pm
Вызов нарколога на дом — это не «универсальная капельница», а управляемая последовательность маленьких шагов с понятными целями и точками проверки. В наркологической клинике «КубаньМед Резолюция» выезд врача, инфузионная поддержка и лечение зависимостей складываются в дорожную карту: мы начинаем с короткого триежа, формулируем рабочую гипотезу, включаем минимально достаточный модуль, назначаем «окно оценки» и только затем либо выключаем модуль, либо изменяем одну переменную. Такой подход снижает фармаконагрузку, предотвращает полипрагмазыю и делает динамику прозрачной: пациент и семья видят, что именно помогает и когда вмешательство завершается.
Подробнее – [url=https://narkolog-na-dom-v-krasnodare16.ru/]нарколог на дом недорого[/url]
RodneyMat
28 Oct 25 at 3:52 pm
dreambuyoutlet – Product images appear clear and descriptions easy to read at first glance.
Blaine Gowans
28 Oct 25 at 3:52 pm
В «СтаврМед Центре» используются только современные препараты, прошедшие клинические испытания и одобренные Минздравом. Каждая капельница подбирается индивидуально, в зависимости от длительности запоя, возраста пациента и состояния здоровья. В таблице приведены примеры основных видов растворов, применяемых при выезде нарколога.
Разобраться лучше – [url=https://vyvod-iz-zapoya-stavropol0.ru/]вывод из запоя на дому ставрополь[/url]
Jaimediown
28 Oct 25 at 3:52 pm
Someone essentially assist to make seriously articles I’d state.
That is the first time I frequented your website page and up to now?
I amazed with the research you made to make this particular publish extraordinary.
Wonderful process!
situs toto
28 Oct 25 at 3:53 pm
makeimpacttoday – Checkout process looked user-friendly and payment options appear transparent.
Farrah Cortinez
28 Oct 25 at 3:53 pm
Этот список — памятка на холодильник. Он не раскрывает диагноз, но точно описывает поводы для связи с дежурным врачом. Своевременная эскалация — часть безопасности, а не «подстраховка». Если сомневаетесь — лучше позвонить.
Исследовать вопрос подробнее – [url=https://kapelnicza-ot-zapoya-v-chelyabinske16.ru/]капельница от запоя стоимость[/url]
Davidhic
28 Oct 25 at 3:54 pm
купить диплом в ханты-мансийске [url=http://www.rudik-diplom6.ru]купить диплом в ханты-мансийске[/url] .
Diplomi_eoKr
28 Oct 25 at 3:55 pm
мел бет [url=www.melbetofficialsite.ru]мел бет[/url] .
bk melbet_hvEa
28 Oct 25 at 3:55 pm
Ниже — рабочая матрица на первые часы. Она показывает, как клиническая гипотеза превращается в минимальный шаг, какие индикаторы берём под контроль и по какому сигналу меняем тактику или площадку. Таблица не заменяет очную оценку, но делает логику маршрута ясной для всей семьи.
Получить дополнительные сведения – http://narkolog-na-dom-v-samare16.ru/vyvod-iz-zapoya-samara-narkolog-na-dom/
Mauricetub
28 Oct 25 at 3:58 pm
купить диплом в георгиевске [url=https://rudik-diplom9.ru/]купить диплом в георгиевске[/url] .
Diplomi_rgei
28 Oct 25 at 3:58 pm
kraken ios
кракен обмен
Henryamerb
28 Oct 25 at 3:59 pm
kraken marketplace
кракен зеркало
Henryamerb
28 Oct 25 at 4:00 pm
J’ai un veritable coup de c?ur pour Ruby Slots Casino, on y trouve une energie contagieuse. Le catalogue est un paradis pour les joueurs, incluant des paris sportifs en direct. Il booste votre aventure des le depart. Les agents sont toujours la pour aider. Les retraits sont simples et rapides, mais des offres plus genereuses seraient top. En bref, Ruby Slots Casino merite un detour palpitant. En plus le design est tendance et accrocheur, ce qui rend chaque moment plus vibrant. Un point fort les options variees pour les paris sportifs, renforce la communaute.
http://www.rubyslotscasinopromocodefr.com|
CrimsonHeartis1zef
28 Oct 25 at 4:01 pm
Для наглядности приведена таблица, отражающая распространённые методы лечения и их цели:
Подробнее можно узнать тут – [url=https://narkologicheskaya-clinika-v-samare16.ru/]частная наркологическая клиника в самаре[/url]
Davidzen
28 Oct 25 at 4:03 pm
купить диплом в костроме [url=www.rudik-diplom7.ru]www.rudik-diplom7.ru[/url] .
Diplomi_rePl
28 Oct 25 at 4:04 pm
Отзывы вроде неплохие https://harmony-stroy.ru пока никто ничего тут не берите!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!моя ситуация решится если то я сообщу.Пока кидалово нарисоваывается.Дабы даже о приходе средств человек не сообщает,просто сказал ложи а после оплаты сразу замолчал,хотя сообщения доходили еще.А ты если кинеш то тварь ты последняя.Бобла наверно тут хорошо сделал а совести хватает провинциалов кидать.Ты в курсе что у нас люди на эти бабки 2 месяца живут и не от сладкой жизни гавно у тебя то берут.Бог тебе судья короче!Свечку тебе за здравие каждую неделю если что буду ставить 😉 чтоб ты жил долго и счастливо…
JasonBoomi
28 Oct 25 at 4:05 pm
букмекерская контора мелбет сайт [url=http://melbetofficialsite.ru]букмекерская контора мелбет сайт[/url] .
bk melbet_yqEa
28 Oct 25 at 4:05 pm
kraken darknet
kraken ссылка
Henryamerb
28 Oct 25 at 4:05 pm
Ниже — ориентир для острых часов на дому. Это не жёсткий шаблон, а карта, где ясно: что делаем, чем измеряем, когда пересматриваем. При отсутствии отклика мы меняем один параметр (например, темп инфузии) и назначаем новое окно оценки, не «двигая» всё остальное.
Подробнее тут – [url=https://narkolog-na-dom-saratov0.ru/]нарколог на дом вывод в саратове[/url]
Brucescuse
28 Oct 25 at 4:07 pm
daman-games.live – Mobile version looks perfect; no glitches, fast scrolling, crisp text.
Janee Gurley
28 Oct 25 at 4:08 pm
imgs81.men – Pages loaded fast, images appeared sharp, and formatting stayed consistent.
Cruz Doi
28 Oct 25 at 4:08 pm
частный seo оптимизатор [url=http://optimizaciya-i-seo-prodvizhenie-sajtov-moskva-1.ru]частный seo оптимизатор[/url] .
optimizaciya i seo prodvijenie saitov moskva_itPi
28 Oct 25 at 4:12 pm
кракен vpn
kraken зеркало
Henryamerb
28 Oct 25 at 4:12 pm
alarm clock radio with cd player and usb charging [url=www.alarm-radio-clocks.com/]www.alarm-radio-clocks.com/[/url] .
Cd Player Radio Alarm Clocks_znOa
28 Oct 25 at 4:13 pm
discoveryourpotential – Good first impression—hope the content or products deliver value as promised.
Amiee Hodgkinson
28 Oct 25 at 4:14 pm
Je suis fascine par Sugar Casino, ca donne une vibe electrisante. Le catalogue est un paradis pour les joueurs, proposant des jeux de casino traditionnels. Il amplifie le plaisir des l’entree. Les agents sont rapides et pros. Les gains sont transferes rapidement, par ailleurs des offres plus importantes seraient super. Pour conclure, Sugar Casino vaut une visite excitante. En complement la navigation est fluide et facile, ce qui rend chaque session plus excitante. Un plus les options de paris sportifs diversifiees, offre des bonus constants.
http://www.sugarcasino777fr.com|
echodripas4zef
28 Oct 25 at 4:14 pm
бк melbet [url=http://www.melbetofficialsite.ru]бк melbet[/url] .
bk melbet_qiEa
28 Oct 25 at 4:15 pm
купить диплом менеджера [url=http://www.rudik-diplom13.ru]купить диплом менеджера[/url] .
Diplomi_zgon
28 Oct 25 at 4:16 pm
melbet букмекерская контора официальный сайт [url=https://melbetofficialsite.ru/]melbet букмекерская контора официальный сайт[/url] .
bk melbet_pfEa
28 Oct 25 at 4:18 pm
Very nice post. I just stumbled upon your blog and wished to say that I have truly enjoyed browsing
your blog posts. In any case I will be subscribing to your rss feed and I hope you
write again very soon!
1 year mba in malaysia
28 Oct 25 at 4:18 pm
купить диплом юриста [url=http://rudik-diplom9.ru/]купить диплом юриста[/url] .
Diplomi_tfei
28 Oct 25 at 4:18 pm
купить диплом в бузулуке [url=http://rudik-diplom7.ru/]купить диплом в бузулуке[/url] .
Diplomi_zyPl
28 Oct 25 at 4:19 pm
You need to be a ρart of a contest fоr one of the Ьest websites on thе internet.
I most certaіnly will highly recommend tһis site!
Feel free tо visit my web-site: emaths maths tuition – Ariel,
Ariel
28 Oct 25 at 4:20 pm
kraken marketplace
kraken обмен
Henryamerb
28 Oct 25 at 4:20 pm
кракен vk3
kraken зеркало
Henryamerb
28 Oct 25 at 4:21 pm
Do you have a spam problem on this blog; I also am
a blogger, and I was wanting to know your situation; many of us have created some nice procedures and we are looking to exchange methods with others, be sure
to shoot me an e-mail if interested.
FeetFinder selling tips
28 Oct 25 at 4:23 pm
Ich freue mich auf Cat Spins Casino, es entfuhrt in eine Welt voller Spa?. Die Auswahl ist einfach unschlagbar, mit Krypto-kompatiblen Spielen. Der Willkommensbonus ist ein Highlight. Die Mitarbeiter sind immer hilfsbereit. Transaktionen sind zuverlassig und klar, in seltenen Fallen mehr Bonusangebote waren ideal. In Summe, Cat Spins Casino sorgt fur kontinuierlichen Spa?. Nebenbei die Oberflache ist benutzerfreundlich, zum Bleiben einladt. Ein gro?artiges Plus die dynamischen Community-Veranstaltungen, die Community enger verbinden.
Cat Spins|
OmegaFireis9zef
28 Oct 25 at 4:23 pm
Без ИТ нет коммуникации kraken актуальные ссылки kraken актуальные ссылки кракен ссылка kraken kraken официальные ссылки
RichardPep
28 Oct 25 at 4:25 pm
kraken darknet market
kraken СПб
Henryamerb
28 Oct 25 at 4:26 pm
купить диплом историка [url=https://rudik-diplom14.ru/]купить диплом историка[/url] .
Diplomi_rsea
28 Oct 25 at 4:27 pm
купить диплом в нефтекамске [url=rudik-diplom7.ru]купить диплом в нефтекамске[/url] .
Diplomi_tsPl
28 Oct 25 at 4:27 pm
официальный сайт мелбет [url=melbetofficialsite.ru]официальный сайт мелбет[/url] .
bk melbet_usEa
28 Oct 25 at 4:30 pm
best clock radio reviews [url=http://alarm-radio-clocks.com/]http://alarm-radio-clocks.com/[/url] .
Cd Player Radio Alarm Clocks_ogOa
28 Oct 25 at 4:30 pm
купить диплом в каменске-уральском [url=http://www.rudik-diplom7.ru]купить диплом в каменске-уральском[/url] .
Diplomi_efPl
28 Oct 25 at 4:32 pm