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!
plinko game online [url=https://plinko-kz2.ru]https://plinko-kz2.ru[/url]
plinko_kz_jner
20 Aug 25 at 8:43 pm
kra36—-at.com — Надежный и удобный сервис — официальный сайт и подробный обзор даркнет-маркета Kraken. Официальный сайт kraken kra36.at — удобный сервис с множеством функций для пользователей. Узнайте больше и начните пользоваться прямо сейчас!
кракен ссылка, кракен ссылки, ссылка кракен, ссылка кракена, ссылки кракен, сайт кракена, кракен сайты, кракен сайт, сайт кракен, кракен отзывы, зеркала кракен, зеркала кракена, зеркало кракен, зеркало кракена, кракен зеркала, кракен зеркало, даркнет кракен, кракен даркнет, ссылка на кракен, ссылка на кракена, ссылки на кракен, кракен маркетплейс, маркетплейс кракен, кракен магазин, магазин кракен, кракены маркет, kraken ссылка, kraken ссылки, кракен маркет, вход кракен, кракен вход, кракен зайти, kraken зеркала, kraken зеркало, актуальная ссылка кракен, актуальная ссылка кракена, актуальные ссылки кракен, кракен актуальная ссылка, кракен актуальные ссылки, кракен ссылка актуальная, кракен ссылки актуальные, кракен как зайти, зайти на кракен, kraken сайты, сайт kraken, kraken сайт, кракен официальный сайт, официальный сайт кракен, кракен сайт официальный, официальный сайт кракена, сайт кракен официальный, сайт кракена официальный, как зайти на кракен, кракен ссылка тор, кракен тор ссылка, ссылка кракен тор, кракен рабочая ссылка, кракен рабочие ссылки, рабочая ссылка кракен, рабочие ссылки кракен, кракен даркнет маркет, кракен маркет даркнет, кракен сайт ссылка, сайт кракен ссылка, кракен площадка, площадка кракен, кракен сайт магазин, актуальная ссылка на кракен, актуальные ссылки на кракен, кракен маркет песня, песня кракен маркет, кракен зеркало рабочее, кракен рабочее зеркало, рабочее зеркало кракен, кракен официальная ссылка, кракен ссылка официальная, официальная ссылка кракен, ссылка кракена официальная, ссылки кракена официальные, кракен сайт что, kraken маркетплейс, маркетплейс kraken
AndrewSit
20 Aug 25 at 8:43 pm
ставки прогнозы [url=www.stavki-prognozy-two.ru/]www.stavki-prognozy-two.ru/[/url] .
stavki prognozi_bwMr
20 Aug 25 at 8:44 pm
I know this if off topic but I’m looking into starting my own weblog and was curious
what all is needed to get setup? I’m assuming having a
blog like yours would cost a pretty penny? I’m not very web smart so I’m
not 100% positive. Any tips or advice would be greatly appreciated.
Cheers
Wesmere Bitmark
20 Aug 25 at 8:44 pm
Индивидуальный подход к каждому пациенту. Каждый случай уникален, поэтому мы разрабатываем персонализированные программы, учитывающие особенности каждого человека.
Подробнее тут – [url=https://narko-zakodirovat.ru/]вывод из запоя в стационаре[/url]
JeraldHor
20 Aug 25 at 8:45 pm
Your style is really unique in comparison to other folks I have read stuff from.
Many thanks for posting when you’ve got the opportunity, Guess I’ll just bookmark
this blog.
tatagrowthshop.com
20 Aug 25 at 8:47 pm
Тик ток мод на андроид
WilliamBeing
20 Aug 25 at 8:48 pm
https://allmynursejobs.com/author/aziretsurai/
Chriszek
20 Aug 25 at 8:49 pm
блэкспрут онион
RichardPep
20 Aug 25 at 8:54 pm
плинко кз [url=https://plinko3002.ru/]https://plinko3002.ru/[/url]
plinko_kz_gfPa
20 Aug 25 at 8:55 pm
https://www.band.us/page/99655486/
Howardhib
20 Aug 25 at 8:55 pm
stavkiprognozy [url=stavki-prognozy-2.ru]stavki-prognozy-2.ru[/url] .
stavki prognozy_gbmn
20 Aug 25 at 8:55 pm
Hi there! This is my first visit to your blog! We are
a collection of volunteers and starting a new project
in a community in the same niche. Your blog provided us beneficial information to work on. You have done a outstanding job!
dovbook.com
20 Aug 25 at 8:57 pm
It’s appropriate time to make a few plans for
the long run and it’s time to be happy. I have read this post and if I may just I want to counsel you some interesting
issues or suggestions. Perhaps you could write subsequent articles referring to this article.
I want to learn even more issues about it!
زمان مصاحبه فرهنگیان ۱۴۰۴
20 Aug 25 at 8:57 pm
Good article! We will be linking to this particularly great post
on our site. Keep up the great writing.
can i charge solar lights indoors
20 Aug 25 at 8:57 pm
I savour, lead to I discovered just what I used to be looking for.
You’ve ended my four day lengthy hunt! God Bless you man.
Have a nice day. Bye
Cheers
20 Aug 25 at 8:58 pm
Hmm it seems like your website ate my first comment (it was super long) so I guess I’ll just sum it up what I wrote and say, I’m thoroughly enjoying your blog.
I as well am an aspiring blog blogger but I’m still
new to everything. Do you have any tips for novice blog writers?
I’d genuinely appreciate it.
Airtogel
20 Aug 25 at 9:01 pm
Stavki Prognozy [url=stavki-prognozy-two.ru]stavki-prognozy-two.ru[/url] .
stavki prognozi_ytMr
20 Aug 25 at 9:02 pm
Hi there everybody, here every person is sharing such know-how, thus it’s fastidious to read this weblog, and I used to visit this weblog every day.
79Club ac
20 Aug 25 at 9:03 pm
plinko [url=www.plinko-kz2.ru]www.plinko-kz2.ru[/url]
plinko_kz_oqer
20 Aug 25 at 9:07 pm
excellent issues altogether, you simply gained a new reader.
What might you suggest in regards to your post that you simply made some
days ago? Any sure?
koitoto
20 Aug 25 at 9:10 pm
https://say.la/read-blog/126398
Chriszek
20 Aug 25 at 9:10 pm
лечение запоя смоленск
vivod-iz-zapoya-smolensk010.ru
вывод из запоя круглосуточно
narkologiyasmolenskNeT
20 Aug 25 at 9:12 pm
Dove acquistare abilify economico prezzi
Posso ottenere abilify economico in vendita
20 Aug 25 at 9:12 pm
I’ve been browsing online more than 3 hours these days, but I
never found any interesting article like yours. It is pretty value enough for me.
In my opinion, if all website owners and bloggers made good content material as you did, the internet shall be much more helpful
than ever before.
Temiz Corebit
20 Aug 25 at 9:13 pm
ставки прогнозы [url=http://www.stavki-prognozy-one.ru]http://www.stavki-prognozy-one.ru[/url] .
stavki prognozi_xpsr
20 Aug 25 at 9:14 pm
https://kamameds.shop/# Safe access to generic ED medication
Danielchumn
20 Aug 25 at 9:18 pm
база психологов онлайн
Charliesoall
20 Aug 25 at 9:18 pm
I am really enjoying the theme/design of your site.
Do you ever run into any web browser compatibility issues?
A number of my blog visitors have complained about my site not working
correctly in Explorer but looks great in Firefox. Do you have any tips to help fix this problem?
Immediate Zun C4
20 Aug 25 at 9:21 pm
sildalis sildenafil tadalafil: does cialis lowers blood pressure – tadalafil citrate bodybuilding
RichardTit
20 Aug 25 at 9:22 pm
оценка доли ооо оценка стоимости заказать
ocenochnaya-kompaniya-586
20 Aug 25 at 9:23 pm
бонусный счет 1вин [url=https://1win22097.ru/]https://1win22097.ru/[/url]
1win_rrpr
20 Aug 25 at 9:23 pm
купить аттестат за 11 класс в ставрополе [url=http://arus-diplom23.ru/]купить аттестат за 11 класс в ставрополе[/url] .
Diplomi_viSr
20 Aug 25 at 9:24 pm
aviator 1win [url=https://1win22097.ru/]https://1win22097.ru/[/url]
1win_unpr
20 Aug 25 at 9:25 pm
cialis contraindications: Tadalify – Tadalify
RichardTit
20 Aug 25 at 9:30 pm
Есть ситуации, когда вызов врача на дом становится не просто желателен, а жизненно необходим. Если зависимый человек не способен самостоятельно прекратить употребление алкоголя или наркотиков, а его самочувствие заметно ухудшается, необходимо незамедлительно обратиться за медицинской помощью. Поводом для вызова нарколога служат следующие опасные симптомы:
Получить дополнительные сведения – http://narcolog-na-dom-novosibirsk0.ru
ThomasReT
20 Aug 25 at 9:31 pm
You could certainly see your skills within the article you write.
The arena hopes for more passionate writers such
as you who are not afraid to say how they believe.
Always go after your heart.
AlpGoxPro
20 Aug 25 at 9:31 pm
https://www.montessorijobsuk.co.uk/author/ygfoyfqqlac/
Chriszek
20 Aug 25 at 9:31 pm
Secret Billionaire Frequency is an intriguing program that focuses
on using specific sound vibrations to rewire the mind for wealth, success,
and abundance. It’s designed to help clear mental blocks,
boost confidence, and align thoughts with prosperity.
Many people find it appealing because it’s simple to use
daily and offers a unique, non-invasive approach to attracting financial growth and opportunities.
Secret Billionaire Frequency
20 Aug 25 at 9:31 pm
Link exchange is nothing else however it is just placing the other
person’s webpage link on your page at suitable place and other person will
also do same in support of you.
КТ
20 Aug 25 at 9:33 pm
https://wanderlog.com/view/xntspzmeol/купить-экстази-кокаин-амфетамин-гент/shared
Howardhib
20 Aug 25 at 9:34 pm
This paragraph offers clear idea for the new viewers of blogging, that
genuinely how to do blogging and site-building.
دفترچه انتخاب رشته فرهنگیان ۱۴۰۴
20 Aug 25 at 9:36 pm
plinko slot [url=http://plinko-kz2.ru/]http://plinko-kz2.ru/[/url]
plinko_kz_eser
20 Aug 25 at 9:36 pm
plinko game [url=https://plinko3001.ru/]https://plinko3001.ru/[/url]
plinko_kz_tzEr
20 Aug 25 at 9:37 pm
Thankfulness to my father who told me regarding this website,
this website is truly awesome.
bitpott solar lights
20 Aug 25 at 9:40 pm
ED treatment without doctor visits: Fast-acting ED solution with discreet packaging – Safe access to generic ED medication
RichardTit
20 Aug 25 at 9:40 pm
скачать 1вин [url=https://1win22097.ru]https://1win22097.ru[/url]
1win_tlpr
20 Aug 25 at 9:41 pm
stavkiprognozy [url=www.stavki-prognozy-two.ru]www.stavki-prognozy-two.ru[/url] .
stavki prognozi_bmMr
20 Aug 25 at 9:41 pm
When I initially commented I clicked the “Notify me when new comments are added” checkbox and now each
time a comment is added I get three e-mails with the same comment.
Is there any way you can remove people from that service?
Cheers!
homepage
20 Aug 25 at 9:43 pm
Today, I went to the beach with my kids. I found
a sea shell and gave it to my 4 year old daughter and said “You can hear the ocean if you put this to your ear.” She put
the shell to her ear and screamed. There was a hermit crab inside and it pinched
her ear. She never wants to go back! LoL I know this is
totally off topic but I had to tell someone!
best rechargeable solar batteries
20 Aug 25 at 9:44 pm