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!
перепланировка услуги [url=http://soglasovanie-pereplanirovki-kvartiry3.ru]http://soglasovanie-pereplanirovki-kvartiry3.ru[/url] .
soglasovanie pereplanirovki kvartiri _unPi
18 Oct 25 at 11:08 pm
соглосование [url=https://www.soglasovanie-pereplanirovki-kvartiry11.ru]https://www.soglasovanie-pereplanirovki-kvartiry11.ru[/url] .
soglasovanie pereplanirovki kvartiri _qmMi
18 Oct 25 at 11:09 pm
узаконить перепланировку в москве цена [url=http://zakazat-proekt-pereplanirovki-kvartiry11.ru]http://zakazat-proekt-pereplanirovki-kvartiry11.ru[/url] .
zakazat proekt pereplanirovki kvartiri_wwet
18 Oct 25 at 11:11 pm
заказать перепланировку квартиры в москве [url=http://proekt-pereplanirovki-kvartiry17.ru/]http://proekt-pereplanirovki-kvartiry17.ru/[/url] .
proekt pereplanirovki kvartiri_iwml
18 Oct 25 at 11:11 pm
Spinrise Casino
Angelolix
18 Oct 25 at 11:11 pm
Вывод из запоя — первый шаг к новой жизни. Узнайте, как безопасно пройти детоксикацию и вернуть здоровье — читайте на dettka.com/vyvod-iz-zapoya-put-k-zdorovoj-zhizni Подробнее тут – http://mymoscow.forum24.ru/?1-3-0-00000684-000-0-0-1757530732
Crystaldum
18 Oct 25 at 11:12 pm
купить диплом журналиста [url=http://rudik-diplom13.ru/]купить диплом журналиста[/url] .
Diplomi_lyon
18 Oct 25 at 11:12 pm
согласование перепланировки в москве [url=http://zakazat-proekt-pereplanirovki-kvartiry11.ru]http://zakazat-proekt-pereplanirovki-kvartiry11.ru[/url] .
zakazat proekt pereplanirovki kvartiri_lget
18 Oct 25 at 11:13 pm
Так как безопасность и анонимность выступают ключевыми аспектами при взаимодействии с подобными ресурсами, поиск надежного канала доступа играет определяющую роль. Использование сомнительных ссылок может привести к краже аккаунта и финансовых средств, поэтому необходимо проявлять особую осторожность. [url=https://www.vortekshavacilik.com.tr/]кракен даркнет только через тор[/url] Именно данный ресурс представляет собой официально рекомендованный способ входа, который не только обеспечивает бесперебойное подключение с серверами маркетплейса, но и надежно защищает конфиденциальность вашей информации от многочисленных фишинговых атак. Мы настоятельно советуем сохранить этот адрес, чтобы в дальнейшем избежать длительных и рискованных поисков.
Othex
18 Oct 25 at 11:13 pm
ставки на хоккей прогнозы [url=http://prognozy-na-khokkej4.ru]http://prognozy-na-khokkej4.ru[/url] .
prognozi na hokkei_cgOl
18 Oct 25 at 11:15 pm
сайт мелбет [url=melbetbonusy.ru]сайт мелбет[/url] .
melbet_rgOi
18 Oct 25 at 11:15 pm
купить диплом в энгельсе [url=www.rudik-diplom3.ru/]www.rudik-diplom3.ru/[/url] .
Diplomi_toei
18 Oct 25 at 11:16 pm
перепланировка и согласование [url=www.soglasovanie-pereplanirovki-kvartiry4.ru]www.soglasovanie-pereplanirovki-kvartiry4.ru[/url] .
soglasovanie pereplanirovki kvartiri _ovOr
18 Oct 25 at 11:16 pm
Купить диплом колледжа в Донецк [url=https://educ-ua7.ru]https://educ-ua7.ru[/url] .
Diplomi_emea
18 Oct 25 at 11:17 pm
купить диплом в миассе [url=https://www.rudik-diplom1.ru]купить диплом в миассе[/url] .
Diplomi_ller
18 Oct 25 at 11:18 pm
фрибет от мелбет [url=www.melbetbonusy.ru/]фрибет от мелбет[/url] .
melbet_xuOi
18 Oct 25 at 11:19 pm
перепланировка москва [url=https://soglasovanie-pereplanirovki-kvartiry11.ru]https://soglasovanie-pereplanirovki-kvartiry11.ru[/url] .
soglasovanie pereplanirovki kvartiri _lvMi
18 Oct 25 at 11:19 pm
стоимость перепланировки в бти [url=https://stoimost-soglasovaniya-pereplanirovki-kvartiry.ru]https://stoimost-soglasovaniya-pereplanirovki-kvartiry.ru[/url] .
stoimost soglasovaniya pereplanirovki kvartiri_auPt
18 Oct 25 at 11:19 pm
соглосование [url=http://soglasovanie-pereplanirovki-kvartiry4.ru]http://soglasovanie-pereplanirovki-kvartiry4.ru[/url] .
soglasovanie pereplanirovki kvartiri _hqOr
18 Oct 25 at 11:20 pm
кракен ссылка
кракен vk2
JamesDaync
18 Oct 25 at 11:23 pm
https://rant.li/ecoifyibmiu/kupit-marikhuanu-dlia-kureniia-v-novosibirske
Anthonycam
18 Oct 25 at 11:24 pm
Выведение из запоя в стационаре Воронежа — помощь при острых состояниях и хронической зависимости. Наши опытные наркологи используют современные методы лечения для быстрого и безопасного вывода из запоя.
Углубиться в тему – [url=https://vyvod-iz-zapoya-v-stacionare-voronezh22.ru/]вывод из запоя в стационаре клиника в воронеже[/url]
RichardJuids
18 Oct 25 at 11:25 pm
перепланировка помещения [url=http://www.soglasovanie-pereplanirovki-kvartiry3.ru]http://www.soglasovanie-pereplanirovki-kvartiry3.ru[/url] .
soglasovanie pereplanirovki kvartiri _wePi
18 Oct 25 at 11:25 pm
Yesterday, while I was at work, my sister stole my iphone and tested to see if it
can survive a 30 foot drop, just so she can be a youtube sensation. My
apple ipad is now broken and she has 83 views. I know this is completely off topic
but I had to share it with someone!
hardcore
18 Oct 25 at 11:26 pm
цена ремонта с перепланировкой [url=http://zakazat-proekt-pereplanirovki-kvartiry11.ru]http://zakazat-proekt-pereplanirovki-kvartiry11.ru[/url] .
zakazat proekt pereplanirovki kvartiri_ccet
18 Oct 25 at 11:26 pm
перепланировка квартир [url=https://www.soglasovanie-pereplanirovki-kvartiry14.ru]https://www.soglasovanie-pereplanirovki-kvartiry14.ru[/url] .
soglasovanie pereplanirovki kvartiri _xaEl
18 Oct 25 at 11:26 pm
купить диплом в донском [url=https://rudik-diplom11.ru/]https://rudik-diplom11.ru/[/url] .
Diplomi_caMi
18 Oct 25 at 11:27 pm
купить диплом занесением реестр [url=www.frei-diplom4.ru/]купить диплом занесением реестр[/url] .
Diplomi_muOl
18 Oct 25 at 11:27 pm
диплом с реестром купить [url=www.frei-diplom3.ru/]диплом с реестром купить[/url] .
Diplomi_ebKt
18 Oct 25 at 11:28 pm
услуги по согласованию перепланировки [url=www.soglasovanie-pereplanirovki-kvartiry11.ru/]www.soglasovanie-pereplanirovki-kvartiry11.ru/[/url] .
soglasovanie pereplanirovki kvartiri _yzMi
18 Oct 25 at 11:28 pm
мелбет фрибет 500 [url=https://melbetbonusy.ru/]мелбет фрибет 500[/url] .
melbet_vnOi
18 Oct 25 at 11:28 pm
купить диплом с занесением реестра [url=www.frei-diplom5.ru]купить диплом с занесением реестра[/url] .
Diplomi_msPa
18 Oct 25 at 11:31 pm
услуги по согласованию перепланировки квартиры [url=www.soglasovanie-pereplanirovki-kvartiry11.ru/]www.soglasovanie-pereplanirovki-kvartiry11.ru/[/url] .
soglasovanie pereplanirovki kvartiri _urMi
18 Oct 25 at 11:33 pm
купить диплом железнодорожника [url=http://rudik-diplom8.ru/]купить диплом железнодорожника[/url] .
Diplomi_kyMt
18 Oct 25 at 11:33 pm
перепланировка помещения [url=https://www.soglasovanie-pereplanirovki-kvartiry4.ru]перепланировка помещения[/url] .
soglasovanie pereplanirovki kvartiri _ezOr
18 Oct 25 at 11:33 pm
Если домашние методы не помогают, вывод из запоя в стационаре в Самаре — это безопасный выбор с профессиональной детоксикацией.
Подробнее тут – http://vyvod-iz-zapoya-v-stacionare-samara24.ru
Williamgaita
18 Oct 25 at 11:34 pm
Spinrise Casino
Angelolix
18 Oct 25 at 11:34 pm
купить диплом в набережных челнах [url=http://www.rudik-diplom5.ru]купить диплом в набережных челнах[/url] .
Diplomi_sxma
18 Oct 25 at 11:34 pm
купить диплом о среднем образовании в реестр [url=www.frei-diplom2.ru]купить диплом о среднем образовании в реестр[/url] .
Diplomi_owEa
18 Oct 25 at 11:35 pm
проект перепланировки цена [url=https://www.proekt-pereplanirovki-kvartiry17.ru]проект перепланировки цена[/url] .
proekt pereplanirovki kvartiri_lqml
18 Oct 25 at 11:35 pm
прогноз ставок на хоккей [url=http://www.prognozy-na-khokkej4.ru]http://www.prognozy-na-khokkej4.ru[/url] .
prognozi na hokkei_rsOl
18 Oct 25 at 11:36 pm
dove comprare Cialis in Italia: tadalafil senza ricetta – farmacia online italiana Cialis
RaymondNit
18 Oct 25 at 11:36 pm
telecharger 1xbet pour android melbet telecharger
parifoot-837
18 Oct 25 at 11:38 pm
бонус мелбет условия [url=melbetbonusy.ru]бонус мелбет условия[/url] .
melbet_mrOi
18 Oct 25 at 11:38 pm
купить диплом учителя [url=rudik-diplom11.ru]купить диплом учителя[/url] .
Diplomi_baMi
18 Oct 25 at 11:38 pm
помощь в согласовании перепланировки квартиры [url=soglasovanie-pereplanirovki-kvartiry11.ru]soglasovanie-pereplanirovki-kvartiry11.ru[/url] .
soglasovanie pereplanirovki kvartiri _ekMi
18 Oct 25 at 11:40 pm
купить диплом в крыму [url=https://rudik-diplom8.ru]купить диплом в крыму[/url] .
Diplomi_tsMt
18 Oct 25 at 11:40 pm
When I initially commented I seem to have clicked
the -Notify me when new comments are added- checkbox and from now on whenever a comment is added I
receive 4 emails with the exact same comment. There has to be a
means you are able to remove me from that service? Thanks a lot!
Futuro Token のレビュー
18 Oct 25 at 11:40 pm
Среди онлайн-кинотеатров Kinoman HD уверенно держит высокую планку: тут вы найдёте свежие премьеры 2024–2025 и любимую классику, удобные фильтры по жанрам, странам и годам ускоряют поиск, а разрешения HD 720, FHD 1080 и 4K обеспечивают эффект полноценного кино. База постоянно обновляется, разделы «Топ 2025», подборки по Marvel и DC плюс поджанры помогают быстро ориентироваться. Ищете фильм онлайн ужасы? Перейдите на kinomanhq.pro — и ваш следующий идеальный фильм найдётся за секунды.
xarajTog
18 Oct 25 at 11:41 pm
сколько стоит согласование перепланировки квартиры [url=https://stoimost-soglasovaniya-pereplanirovki-kvartiry.ru/]https://stoimost-soglasovaniya-pereplanirovki-kvartiry.ru/[/url] .
stoimost soglasovaniya pereplanirovki kvartiri_emPt
18 Oct 25 at 11:42 pm