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=https://www.arus-diplom34.ru]диплом о высшем образовании купить с занесением в реестр[/url] .
Zakazat diplom ob obrazovanii!_etkn
30 Jul 25 at 9:24 pm
сайт точных прогнозов на футбол [url=http://kompyuternye-prognozy-na-futbol8.ru]http://kompyuternye-prognozy-na-futbol8.ru[/url] .
komputernie prognozi na fytbol_zlsi
30 Jul 25 at 9:27 pm
can i buy cheap oxytrol without dr prescription
can you buy oxytrol without rx
30 Jul 25 at 9:39 pm
order Provigil without prescription: Wake Meds RX – order Provigil without prescription
Ralphpek
30 Jul 25 at 9:41 pm
Asking questions are actually fastidious thing if you are not understanding anything entirely, except this paragraph provides fastidious understanding even.
Feel free to surf to my website makkelijk internet aanvragen in Hongarije
makkelijk internet aanvragen in Hongarije
30 Jul 25 at 9:46 pm
диплом о высшем купить [url=http://arus-diplom7.ru/]диплом о высшем купить[/url] .
Zakazat diplom yniversiteta!_hfOt
30 Jul 25 at 9:49 pm
Клиника Частный Медик?24 в Коломне — профессиональная капельница от запоя в стационаре, смотрите страницу услуги.
Исследовать вопрос подробнее – [url=https://kapelnica-ot-zapoya-kolomna15.ru/]капельница от запоя клиника в коломне[/url]
MatthewNouff
30 Jul 25 at 9:50 pm
I’m not sure where you are getting your information, but good
topic. I needs to spend some time learning much more or understanding more.
Thanks for magnificent information I was looking for this information for
my mission.
designs-tab-open
30 Jul 25 at 9:53 pm
На основе полученных диагностических данных врач подбирает оптимальные препараты и дозировки, разрабатывая персональный план лечебных мероприятий.
Подробнее можно узнать тут – [url=https://narcolog-na-dom-voronezh00.ru/]narkolog-na-dom voronezh[/url]
AlbertVal
30 Jul 25 at 9:54 pm
В Красноярске используется широкий спектр современных методик для вывода из запоя. Комплексное лечение включает в себя несколько этапов, позволяющих обеспечить быструю детоксикацию и восстановление организма. Основное внимание уделяется индивидуальному подходу, что позволяет адаптировать терапию под конкретные потребности каждого пациента.
Выяснить больше – [url=https://vyvod-iz-zapoya-krasnoyarsk66.ru/]вывод из запоя капельница на дому красноярск[/url]
MichaelViamb
30 Jul 25 at 9:55 pm
Mega darknet
RichardPep
30 Jul 25 at 9:59 pm
My coder is trying to persuade me to move
to .net from PHP. I have always disliked the idea because of the expenses.
But he’s tryiong none the less. I’ve been using Movable-type on several websites for about a year and
am worried about switching to another platform. I have
heard great things about blogengine.net. Is there a way
I can transfer all my wordpress content into it? Any kind of help would
be really appreciated!
my web-site … Hungary internet without Hungarian ID
Hungary internet without Hungarian ID
30 Jul 25 at 9:59 pm
Когда организм на пределе, важна срочная помощь в Ростове-На-Дону — это команда опытных наркологов, которые помогут быстро и мягко выйти из запоя без вреда для здоровья.
Получить профессиональную консультацию – [url=https://vyvod-iz-zapoya-rostov11.ru/]срочный вывод из запоя город ростов-на-дону[/url]
Gregorysunda
30 Jul 25 at 9:59 pm
Портал с обзорами лучших онлайн-казино, рейтингами, актуальными бонусами и акциями, а также подробными гайдами и промо-предложениями: топ 10 лучших онлайн казино
Bobbyved
30 Jul 25 at 10:01 pm
обучение кайтсёрфингу Кайтсерфинг на Маврикии: Ле Морн
Kennethvut
30 Jul 25 at 10:01 pm
перевозка легковых автомобилей автовозом [url=avtovoz-av7.ru]avtovoz-av7.ru[/url] .
avtovoz_wmst
30 Jul 25 at 10:05 pm
Узнайте про выведение из запоя в стационаре в Частном Медике 24 (Балашиха) по ссылке.
Интересует подробная информация – [url=https://vyvod-iz-zapoya-v-stacionare-balashiha13.ru/]вывод из запоя в стационаре в балашихе[/url]
DonaldGueni
30 Jul 25 at 10:12 pm
Современные методы лечения при выводе из запоя включают как медикаментозную детоксикацию, так и психологическую реабилитацию. В Уфе наркологи используют капельничное введение лекарственных средств, которые помогают быстро вывести токсины, нормализовать обмен веществ и стабилизировать работу внутренних органов. Одновременно с этим проводится психологическая поддержка для снижения эмоционального стресса, связанного с запоем.
Исследовать вопрос подробнее – [url=https://narcolog-na-dom-ufa0.ru/]нарколог уфа[/url]
Williamtathy
30 Jul 25 at 10:13 pm
Лечение проводится непосредственно в домашних условиях, что позволяет избежать стресса, связанного с пребыванием в стационаре. Применение современных медикаментов и индивидуальный подход к выбору терапии обеспечивают безопасность и эффективность процедуры.
Получить дополнительную информацию – [url=https://narcolog-na-dom-v-irkutske66.ru/]нарколог на дом анонимно[/url]
Michaellomia
30 Jul 25 at 10:15 pm
You really make it appear really easy together with your presentation but I to find this topic to
be really something which I think I’d never understand.
It kind of feels too complex and extremely broad for
me. I’m having a look forward in your subsequent put up,
I will try to get the hold of it!
dewatogel link
30 Jul 25 at 10:15 pm
перевозка легковых автомобилей автовозом [url=avtovoz-av7.ru]avtovoz-av7.ru[/url] .
avtovoz_sost
30 Jul 25 at 10:16 pm
Thanks for one’s marvelous posting! I definitely enjoyed reading it, you’re a great author.
I will be sure to bookmark your blog and may come back at some point.
I want to encourage yourself to continue your great job,
have a nice weekend!
Sleep Lean Reviews
30 Jul 25 at 10:19 pm
кайтсёрфинг “Кайтлупы”: Экстремальные трюки для опытных райдеров
Kennethvut
30 Jul 25 at 10:19 pm
В таких случаях своевременное обращение за помощью позволяет быстро стабилизировать состояние и предотвратить развитие серьезных осложнений.
Получить дополнительные сведения – https://narcolog-na-dom-voronezh0.ru/vyzov-narkologa-na-dom-voronezh
ArthurVes
30 Jul 25 at 10:26 pm
доставка авто из тольятти [url=avtovoz-av.ru]avtovoz-av.ru[/url] .
avtovoz_aumr
30 Jul 25 at 10:26 pm
перевозка авто автовозом по россии [url=http://avtovoz-av7.ru/]http://avtovoz-av7.ru/[/url] .
avtovoz_ykst
30 Jul 25 at 10:28 pm
It’s appropriate time to make some plans for the future and
it is time to be happy. I’ve read this put up and if
I may just I desire to recommend you some interesting issues or suggestions.
Maybe you can write next articles referring to this article.
I desire to read more issues approximately it!
منابع درسی دانشگاه پیام نور
30 Jul 25 at 10:28 pm
Its like you read my mind! You appear to know a lot about this, like you wrote the book in it or something.
I think that you can do with a few pics to drive the message home a bit, but instead of that,
this is excellent blog. A great read. I’ll definitely be back.
Accounting assignment help UK
30 Jul 25 at 10:32 pm
автоперевозка автомобилей по россии [url=http://avtovoz-av.ru/]http://avtovoz-av.ru/[/url] .
avtovoz_fsmr
30 Jul 25 at 10:37 pm
перевозка автомобиля автовозом по россии [url=https://avtovoz-av7.ru/]avtovoz-av7.ru[/url] .
avtovoz_kbst
30 Jul 25 at 10:38 pm
Hello this is kinda of off topic but I was wanting to
know if blogs use WYSIWYG editors or if you have to manually
code with HTML. I’m starting a blog soon but have no coding experience so I wanted to get advice from
someone with experience. Any help would be greatly appreciated!
sihoki login
30 Jul 25 at 10:39 pm
где купить аттестат за 11 класс 2015 [url=www.arus-diplom22.ru/]где купить аттестат за 11 класс 2015[/url] .
Diplomi_zjsl
30 Jul 25 at 10:40 pm
перевозка легковых автомобилей автовозом [url=http://avtovoz-av7.ru]http://avtovoz-av7.ru[/url] .
avtovoz_vkst
30 Jul 25 at 10:40 pm
I like looking through an article that can make men and women think.
Also, thank you for allowing me to comment!
Titan
30 Jul 25 at 10:54 pm
услуги транспортировки автомобилей [url=http://avtovoz-av7.ru/]http://avtovoz-av7.ru/[/url] .
avtovoz_orst
30 Jul 25 at 10:56 pm
В Ростове-На-Дону решение есть — наркологическая клиника. Здесь помогают людям выйти из запоя без страха и осуждения. Всё анонимно, грамотно и с заботой о каждом пациенте.
Раскрыть тему полностью – http://vyvod-iz-zapoya-rostov15.ru
NormanOpeft
30 Jul 25 at 10:57 pm
amoxicillin 500 coupon: amoxicillin 30 capsules price – Clear Meds Direct
BrianTub
30 Jul 25 at 10:59 pm
Hi! I just wish to give you a big thumbs up for the great info you have right here on this post.
I’ll be coming back to your site for more soon.
talkandheal.org
30 Jul 25 at 10:59 pm
где купить аттестат за 11 класс екатеринбург [url=www.arus-diplom22.ru]где купить аттестат за 11 класс екатеринбург[/url] .
Diplomi_dqsl
30 Jul 25 at 11:02 pm
прогнозы на хоккей на сегодня бесплатно [url=https://luchshie-prognozy-na-khokkej6.ru/]https://luchshie-prognozy-na-khokkej6.ru/[/url] .
lychshie prognozi na hokkei_lqMi
30 Jul 25 at 11:03 pm
Sildenafil is the active ingredient in Viagra. Viagra is a brand name for the medication containing sildenafil.
Both are used to treat erectile dysfunction, but sildenafil is the generic version while Viagra is
the brand name version.
viagra pdf
30 Jul 25 at 11:03 pm
Клиника «НаркоЩит» предоставляет возможность безопасного вывода из запоя на дому в Нижнем Новгороде и Нижегородской области с помощью установки капельницы. Наши опытные специалисты оперативно приезжают для проведения детоксикации, снятия симптомов алкогольной интоксикации и стабилизации состояния пациента. Мы гарантируем круглосуточный выезд, соблюдение конфиденциальности и высокий уровень профессионального обслуживания.
Подробнее – [url=https://kapelnica-ot-zapoya-nizhniy-novgorod00.ru/]капельница от запоя на дому в нижний новгороде[/url]
RobertTIX
30 Jul 25 at 11:06 pm
автоперевозка автомобилей по россии [url=http://avtovoz-av7.ru/]http://avtovoz-av7.ru/[/url] .
avtovoz_xtst
30 Jul 25 at 11:07 pm
кайт Ремонт кайта: своими руками
Kennethvut
30 Jul 25 at 11:07 pm
перевозка автомобиля автовозом по россии [url=https://avtovoz-av.ru]https://avtovoz-av.ru[/url] .
avtovoz_vumr
30 Jul 25 at 11:08 pm
Its like you read my mind! You seem to know so much about this, like you
wrote the book in it or something. I think that
you could do with some pics to drive the message home a little bit, but instead of that, this is great blog.
An excellent read. I’ll definitely be back.
homepage
30 Jul 25 at 11:15 pm
перевозка автомобилей автовозом по россии [url=https://www.avtovoz-av.ru]https://www.avtovoz-av.ru[/url] .
avtovoz_aqmr
30 Jul 25 at 11:19 pm
anti-inflammatory steroids online: ReliefMeds USA – 200 mg prednisone daily
LarryBoymn
30 Jul 25 at 11:19 pm
В Ростове-На-Дону решение есть — наркологическая клиника. Здесь помогают людям выйти из запоя без страха и осуждения. Всё анонимно, грамотно и с заботой о каждом пациенте.
Проверенные методы — узнай сейчас – http://vyvod-iz-zapoya-rostov12.ru/
GeraldNuh
30 Jul 25 at 11:20 pm
перевозка автомобиля автовозом по россии [url=avtovoz-av.ru]avtovoz-av.ru[/url] .
avtovoz_qcmr
30 Jul 25 at 11:22 pm