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!
Cabinet IQ Austin
2419 Ⴝ Bell Blvd, Ceedar Park,
TX 78613, United Ꮪtates
+12543183528
Wood
Wood
5 Oct 25 at 6:03 am
I think the admin of this site is actually working hard for his web page, as
here every data is quality based material.
CalvenRidge Trust Review
5 Oct 25 at 6:03 am
With havin so much content do you ever run into any issues of plagorism or copyright infringement?
My website has a lot of exclusive content I’ve either authored myself or
outsourced but it looks like a lot of it is popping it up all over the
internet without my permission. Do you know any techniques
to help protect against content from being stolen? I’d truly appreciate it.
Astera Miner AI Review
5 Oct 25 at 6:04 am
кракен сайт магазин позволяет обойти возможные блокировки и получить доступ к маркетплейсу. [url=https://www.rcgauto.com/]кракен даркнет[/url] необходимо искать через проверенные источники, чтобы избежать фишинговых сайтов. кракен рабочее зеркало должно обновляться регулярно для обеспечения непрерывного доступа.
регистрация – главная особенность Кракен.
KrakenOthex
5 Oct 25 at 6:04 am
Slot88resmi provider agen slot88 resmi dengan lisensi paling gacor dan terpercaya login di situs slot88resmi.com untuk promo
bonus tanpa batas. Dunia permainan slot online
semakin berkembang pesat dalam beberapa tahun terakhir.
Kehadiran berbagai platform permainan digital membawa pengalaman baru bagi para penggemar judi
online di seluruh dunia, termasuk Indonesia.
slot88resmi
5 Oct 25 at 6:04 am
как купить диплом с занесением в реестр [url=www.frei-diplom2.ru/]как купить диплом с занесением в реестр[/url] .
Diplomi_fqEa
5 Oct 25 at 6:04 am
Приобрести онлайн кокаин, мефедрон, гашиш, бошки
RodneyDof
5 Oct 25 at 6:06 am
купить диплом о высшем образовании реестр [url=http://frei-diplom5.ru/]купить диплом о высшем образовании реестр[/url] .
Diplomi_bgPa
5 Oct 25 at 6:06 am
купить диплом с занесением в реестр челябинск [url=www.frei-diplom6.ru/]купить диплом с занесением в реестр челябинск[/url] .
Diplomi_vvOl
5 Oct 25 at 6:08 am
купить диплом в назрани [url=www.rudik-diplom8.ru]купить диплом в назрани[/url] .
Diplomi_fjMt
5 Oct 25 at 6:08 am
купить диплом хореографа [url=www.rudik-diplom3.ru]купить диплом хореографа[/url] .
Diplomi_xnei
5 Oct 25 at 6:08 am
Купить диплом колледжа в Винница [url=http://educ-ua7.ru/]http://educ-ua7.ru/[/url] .
Diplomi_ldea
5 Oct 25 at 6:08 am
купить диплом в балашихе [url=http://rudik-diplom5.ru/]купить диплом в балашихе[/url] .
Diplomi_npma
5 Oct 25 at 6:09 am
купить диплом в губкине [url=http://www.rudik-diplom2.ru]http://www.rudik-diplom2.ru[/url] .
Diplomi_tjpi
5 Oct 25 at 6:09 am
купить проведенный диплом провести [url=frei-diplom4.ru]купить проведенный диплом провести[/url] .
Diplomi_nxOl
5 Oct 25 at 6:12 am
купить кухню в спб от производителя [url=www.kuhni-spb-4.ru/]купить кухню в спб от производителя[/url] .
kyhni spb_qher
5 Oct 25 at 6:12 am
I am really inspired with your writing talents as smartly as with the structure on your blog.
Is that this a paid theme or did you customize it your
self? Either way stay up the nice quality writing, it’s uncommon to see a great blog like this one nowadays..
trashcanpatrol
5 Oct 25 at 6:13 am
купить диплом в кунгуре [url=www.rudik-diplom7.ru]www.rudik-diplom7.ru[/url] .
Diplomi_ftPl
5 Oct 25 at 6:14 am
sh576.xyz – A few internal links led to blank or error pages, needs cleanup.
Debrah Feutz
5 Oct 25 at 6:14 am
купить диплом в глазове [url=https://www.rudik-diplom8.ru]купить диплом в глазове[/url] .
Diplomi_jcMt
5 Oct 25 at 6:15 am
Купить диплом техникума в Львов [url=educ-ua7.ru]educ-ua7.ru[/url] .
Diplomi_rxea
5 Oct 25 at 6:15 am
купить диплом в кисловодске [url=http://rudik-diplom2.ru]купить диплом в кисловодске[/url] .
Diplomi_kqpi
5 Oct 25 at 6:16 am
глория мебель [url=https://kuhni-spb-4.ru/]https://kuhni-spb-4.ru/[/url] .
kyhni spb_guer
5 Oct 25 at 6:18 am
купить диплом в ставрополе [url=http://www.rudik-diplom4.ru]купить диплом в ставрополе[/url] .
Diplomi_kuOr
5 Oct 25 at 6:20 am
купить диплом техникума с занесением в реестр [url=http://www.frei-diplom1.ru]купить диплом техникума с занесением в реестр[/url] .
Diplomi_mtOi
5 Oct 25 at 6:20 am
Hi! I could have sworn I’ve visited this blog before but after browsing through a few of the articles I realized it’s new to me.
Nonetheless, I’m definitely happy I found it and I’ll be book-marking it and checking back often!
turkey visa for australian
5 Oct 25 at 6:20 am
можно купить диплом медсестры [url=http://frei-diplom14.ru]можно купить диплом медсестры[/url] .
Diplomi_kboi
5 Oct 25 at 6:23 am
Ищете компрессорное оборудование по лучшим ценам? Посетите сайт ПромКомТех https://promcomtech.ru/ и ознакомьтесь с каталогом, в котором вы найдете компрессоры для различных видов деятельности. Мы осуществляем оперативную доставку оборудования и комплектующих по всей России. Подробнее на сайте.
henohstaro
5 Oct 25 at 6:24 am
купить диплом с занесением в реестр новосибирск [url=https://frei-diplom5.ru/]купить диплом с занесением в реестр новосибирск[/url] .
Diplomi_dzPa
5 Oct 25 at 6:25 am
как купить диплом проведенный [url=www.frei-diplom6.ru]как купить диплом проведенный[/url] .
Diplomi_ifOl
5 Oct 25 at 6:26 am
как купить диплом с проводкой [url=www.frei-diplom1.ru]как купить диплом с проводкой[/url] .
Diplomi_fjOi
5 Oct 25 at 6:28 am
купить диплом математика [url=https://www.rudik-diplom3.ru]купить диплом математика[/url] .
Diplomi_oxei
5 Oct 25 at 6:28 am
купить диплом в воткинске [url=www.rudik-diplom4.ru/]купить диплом в воткинске[/url] .
Diplomi_eqOr
5 Oct 25 at 6:28 am
Mighty Dog Roofing
Reimer Drive North 13768
Maple Grove, MN 55311 United Ѕtates
(763) 280-5115
reliable storm damage restoration services
reliable storm damage restoration services
5 Oct 25 at 6:28 am
высшее образование купить диплом с занесением в реестр [url=https://frei-diplom4.ru]высшее образование купить диплом с занесением в реестр[/url] .
Diplomi_grOl
5 Oct 25 at 6:29 am
Apkslot situs resmi provider apk slot 777 dengan bonus mingguan slot terbesar,
provider lengkap, dan jackpot progresif setiap hari.
Dalam dunia hiburan digital saat ini, apk slot menjadi
salah satu kata kunci yang paling banyak dicari oleh para penggemar permainan online,
khususnya di kategori slot. Popularitasnya tidak lepas dari perkembangan teknologi yang semakin memudahkan pemain untuk menikmati permainan slot hanya dengan menggunakan aplikasi di perangkat Android maupun iOS.
apk slot
5 Oct 25 at 6:29 am
купить диплом в черногорске [url=www.rudik-diplom7.ru]www.rudik-diplom7.ru[/url] .
Diplomi_phPl
5 Oct 25 at 6:30 am
купить диплом менеджера по туризму [url=https://rudik-diplom5.ru]купить диплом менеджера по туризму[/url] .
Diplomi_tqma
5 Oct 25 at 6:31 am
Приобрести онлайн кокаин, мефедрон, гашиш, бошки
RodneyDof
5 Oct 25 at 6:32 am
купить диплом с занесением в реестр в иркутске [url=http://www.frei-diplom1.ru]купить диплом с занесением в реестр в иркутске[/url] .
Diplomi_auOi
5 Oct 25 at 6:32 am
The buzz on Minotaurus presale is real, surpassing milestones fast. $MTAUR’s tokenomics prioritize sustainability over quick flips. Game’s whimsical elements shine.
mtaur token
WilliamPargy
5 Oct 25 at 6:33 am
что будет если купить диплом о высшем образовании с занесением в реестр [url=http://frei-diplom5.ru/]что будет если купить диплом о высшем образовании с занесением в реестр[/url] .
Diplomi_rePa
5 Oct 25 at 6:33 am
купить диплом с занесением в реестр в спб [url=https://frei-diplom6.ru/]https://frei-diplom6.ru/[/url] .
Diplomi_zsOl
5 Oct 25 at 6:34 am
диплом купить техникум [url=www.frei-diplom8.ru]диплом купить техникум[/url] .
Diplomi_kgsr
5 Oct 25 at 6:36 am
Советую https://www.multiplechoiceflooring.com/transform-your-home-with-multiple-choice-flooring/?unapproved=8720&moderation-hash=19ac94b2ef2607ce3cb76684c8c8a61a
PedroMop
5 Oct 25 at 6:37 am
купить диплом в кургане [url=http://rudik-diplom4.ru]купить диплом в кургане[/url] .
Diplomi_kkOr
5 Oct 25 at 6:37 am
Refresh Renovation Broomfield
11001 Ꮤ 120th Ave 400 suite 459а,
Broomfield, CO 80021, United Ⴝtates
+13032681372
remodel and small kitchen laundry (http://www.symbaloo.com)
www.symbaloo.com
5 Oct 25 at 6:37 am
медсестра которая купила диплом врача [url=frei-diplom14.ru]frei-diplom14.ru[/url] .
Diplomi_heoi
5 Oct 25 at 6:38 am
купить диплом железнодорожника [url=rudik-diplom5.ru]купить диплом железнодорожника[/url] .
Diplomi_wmma
5 Oct 25 at 6:38 am
купить диплом с реестром отзывы [url=https://www.frei-diplom5.ru]купить диплом с реестром отзывы[/url] .
Diplomi_ydPa
5 Oct 25 at 6:39 am