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!
I couldn’t refrain from commenting. Perfectly written!
local kitchen remodeling service
24 Oct 25 at 1:07 am
bahis sitesi 1xbet [url=www.1xbet-giris-5.com]bahis sitesi 1xbet[/url] .
1xbet giris_wySa
24 Oct 25 at 1:07 am
В жизни крупных городов часто возникают ситуации, когда стрессы и быстрый ритм жизни приводят к развитию зависимости. Когда проблема становится очевидной, важно незамедлительно обратиться за помощью. В таких случаях вызов нарколога на дом может стать не только удобным, но и наиболее эффективным вариантом. Это позволяет получить квалифицированное лечение в привычной обстановке, сохраняя при этом полную анонимность и конфиденциальность.
Подробнее тут – [url=https://narcolog-na-dom-moskva55.ru/]вызвать нарколога на дом срочно[/url]
CharlesEmott
24 Oct 25 at 1:10 am
1xbet tr giri? [url=www.1xbet-giris-9.com/]www.1xbet-giris-9.com/[/url] .
1xbet giris_geon
24 Oct 25 at 1:10 am
Запойное состояние опасно не только токсическим воздействием алкоголя на организм, но и последствиями резкого отказа от спиртного. В таких случаях промедление может стоить здоровья. Нарколог на дом в Рязани приезжает по вызову и проводит процедуру прямо в домашних условиях, используя проверенные медицинские методики. Такой подход сочетает анонимность, оперативность и возможность контроля состояния без госпитализации.
Получить дополнительные сведения – [url=https://narcolog-na-dom-ryazan0.ru/]врач нарколог на дом[/url]
Richardshado
24 Oct 25 at 1:11 am
Бонусы также различаются по формату. Определённые акции предлагаются новичкам. При регистрации на 1xBet, используйте промокод и заберите 100% бонус на первый депозит до 32500 рублей.Платформа 1xBet предлагает своим клиентам играть и делать ставки с использованием специальных бонусов. Это повышает интерес к ставкам и гарантирует максимальную безопасность игры.Действующий код 1xBet можно получить по этой ссылке — http://www.medtronik.ru/images/pages/1hbet_2021_promokod_pri_registracii.html.
JesusJuize
24 Oct 25 at 1:11 am
seo продвижение сайтов агентство [url=www.reiting-seo-kompaniy.ru]www.reiting-seo-kompaniy.ru[/url] .
reiting seo kompanii_ldon
24 Oct 25 at 1:12 am
скачать бк осталось всего только выбрать подходящее [url=1win5518.ru]скачать бк осталось всего только выбрать подходящее[/url]
1win_kg_kqkl
24 Oct 25 at 1:13 am
1xbet g?ncel giri? [url=https://www.1xbet-giris-2.com]1xbet g?ncel giri?[/url] .
1xbet giris_blPt
24 Oct 25 at 1:14 am
кракен даркнет маркет
кракен vk4
kraken marketplace
24 Oct 25 at 1:14 am
kraken обмен
kraken РФ
JamesDaync
24 Oct 25 at 1:16 am
1xbet resmi giri? [url=http://1xbet-giris-2.com/]http://1xbet-giris-2.com/[/url] .
1xbet giris_tzPt
24 Oct 25 at 1:16 am
1 xbet [url=http://1xbet-giris-5.com/]http://1xbet-giris-5.com/[/url] .
1xbet giris_sbSa
24 Oct 25 at 1:16 am
1xbet mobi [url=http://1xbet-giris-1.com]http://1xbet-giris-1.com[/url] .
1xbet giris_wwkt
24 Oct 25 at 1:17 am
1x giri? [url=https://1xbet-giris-4.com/]https://1xbet-giris-4.com/[/url] .
1xbet giris_ldSa
24 Oct 25 at 1:17 am
1xbet ?ye ol [url=https://1xbet-giris-9.com/]https://1xbet-giris-9.com/[/url] .
1xbet giris_hfon
24 Oct 25 at 1:18 am
1вин кг [url=https://1win5519.ru]https://1win5519.ru[/url]
1win_kg_yxEr
24 Oct 25 at 1:19 am
1xbetgiri? [url=https://1xbet-giris-8.com/]1xbet-giris-8.com[/url] .
1xbet giris_zjPn
24 Oct 25 at 1:20 am
баланс ван вин [url=https://1win5518.ru]https://1win5518.ru[/url]
1win_kg_kpkl
24 Oct 25 at 1:21 am
Very good post! We will be linking to this particularly great article on our site.
Keep up the great writing.
natural cosmetics
24 Oct 25 at 1:24 am
Как получить приветственный бонус: краткая инструкция по регистрации и пополнению счёта, включая требований по отыгрышу; в середине параграфа мы указываем ссылку на https://bergkompressor.ru/news/artcles/?1xbet_promokod_pri_registracii_bonus_5.html, чтобы пользователь мог перейти и узнать подробности. Помимо этого приводим примеры доступных типов акций.
Petercet
24 Oct 25 at 1:25 am
1xbet g?ncel giri? [url=https://1xbet-giris-5.com/]1xbet g?ncel giri?[/url] .
1xbet giris_keSa
24 Oct 25 at 1:25 am
https://herengezondheid.com/# Sildenafil zonder recept bestellen
Hermanereli
24 Oct 25 at 1:25 am
It’s difficult to find well-informed people in this particular topic,
however, you sound like you know what you’re talking about!
Thanks
Home remodeling company
24 Oct 25 at 1:26 am
кракен android
kraken darknet
JamesDaync
24 Oct 25 at 1:27 am
1xbet turkiye [url=http://www.1xbet-giris-4.com]http://www.1xbet-giris-4.com[/url] .
1xbet giris_lzSa
24 Oct 25 at 1:27 am
1xbet mobi [url=https://1xbet-giris-2.com]https://1xbet-giris-2.com[/url] .
1xbet giris_scPt
24 Oct 25 at 1:29 am
1xbet g?ncel giri? [url=1xbet-giris-6.com]1xbet g?ncel giri?[/url] .
1xbet giris_cxsl
24 Oct 25 at 1:29 am
kraken vk2
kraken vk3
кракен маркетплейс
24 Oct 25 at 1:30 am
купить аттестат за 9 класс [url=https://rudik-diplom9.ru]купить аттестат за 9 класс[/url] .
Diplomi_uhei
24 Oct 25 at 1:30 am
Очень доволен скоростью и точностью работы брокера. Все документы поданы без задержек, оформление прошло гладко. Видно, что специалисты знают своё дело https://vkobroker.ru/
Brianovalt
24 Oct 25 at 1:32 am
1xbet mobil giri? [url=http://1xbet-giris-9.com]1xbet mobil giri?[/url] .
1xbet giris_vaon
24 Oct 25 at 1:32 am
1xbet ?ye ol [url=www.1xbet-giris-6.com/]www.1xbet-giris-6.com/[/url] .
1xbet giris_emsl
24 Oct 25 at 1:32 am
1xbet t?rkiye giri? [url=https://1xbet-giris-8.com/]1xbet t?rkiye giri?[/url] .
1xbet giris_msPn
24 Oct 25 at 1:33 am
1xbet giri?i [url=https://1xbet-giris-1.com]https://1xbet-giris-1.com[/url] .
1xbet giris_gokt
24 Oct 25 at 1:33 am
1xbet g?ncel [url=https://www.1xbet-giris-5.com]1xbet g?ncel[/url] .
1xbet giris_xcSa
24 Oct 25 at 1:33 am
1xbet giri? 2025 [url=https://1xbet-giris-4.com]https://1xbet-giris-4.com[/url] .
1xbet giris_ljSa
24 Oct 25 at 1:34 am
игра ракета на деньги 1win отзывы [url=https://www.1win5519.ru]https://www.1win5519.ru[/url]
1win_kg_irEr
24 Oct 25 at 1:34 am
После поступления вызова нарколог клиники «АльфаНаркология» оперативно выезжает по указанному адресу. На месте врач проводит первичную диагностику, оценивая степень интоксикации, физическое и психологическое состояние пациента. По результатам осмотра врач подбирает индивидуальный комплекс лечебных процедур, в который входит постановка капельницы с растворами для детоксикации, препараты для стабилизации работы органов и нормализации психического состояния.
Подробнее тут – https://narcolog-na-dom-sankt-peterburg000.ru/vyzov-narkologa-na-dom-spb/
TerryCaf
24 Oct 25 at 1:37 am
кракен маркетплейс
кракен даркнет
кракен vk6
24 Oct 25 at 1:39 am
I am actually grateful to the holder of this website who has
shared this impressive post at here.
riobet casino официальный сайт
24 Oct 25 at 1:39 am
http://confiafarmacia.com/# ConfiaFarmacia
JamesSlilk
24 Oct 25 at 1:40 am
рейтинг seo фирм [url=www.reiting-seo-kompaniy.ru]www.reiting-seo-kompaniy.ru[/url] .
reiting seo kompanii_zson
24 Oct 25 at 1:40 am
кракен онион
кракен vk6
JamesDaync
24 Oct 25 at 1:41 am
1xbet yeni giri? adresi [url=https://1xbet-giris-6.com/]1xbet yeni giri? adresi[/url] .
1xbet giris_ntsl
24 Oct 25 at 1:42 am
This site was… how do you say it? Relevant!!
Finally I have found something that helped me. Appreciate it!
dewascatter
24 Oct 25 at 1:42 am
birxbet [url=www.1xbet-giris-5.com]www.1xbet-giris-5.com[/url] .
1xbet giris_jiSa
24 Oct 25 at 1:42 am
1xbet tr giri? [url=https://1xbet-giris-1.com/]1xbet-giris-1.com[/url] .
1xbet giris_cvkt
24 Oct 25 at 1:43 am
кракен qr код
kraken darknet
JamesDaync
24 Oct 25 at 1:43 am
Ритм жизни в мегаполисе и постоянный стресс часто становятся причиной развития зависимостей у жителей города. В такой ситуации необходима профессиональная консультация врача. Оптимальное решение – вызов нарколога на дом в Москве. Это обеспечивает не только получение медицинской помощи в привычной обстановке, но и полную конфиденциальность.
Получить дополнительные сведения – [url=https://narcolog-na-dom-msk55.ru/]вызов врача нарколога на дом[/url]
Willieshilk
24 Oct 25 at 1:44 am