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!
Quality posts is the key to be a focus for the users to pay a visit the
web site, that’s what this site is providing.
Wilmington water heater repair
26 Oct 25 at 7:26 am
Touche. Great arguments. Keep up the good spirit.
HZ99
26 Oct 25 at 7:27 am
1xbet t?rkiye giri? [url=http://1xbet-12.com]1xbet t?rkiye giri?[/url] .
1xbet_sySr
26 Oct 25 at 7:27 am
Everything in One Place: https://www.home-truths.co.uk
BryanAlarl
26 Oct 25 at 7:28 am
1xbet resmi sitesi [url=1xbet-13.com]1xbet-13.com[/url] .
1xbet_qqKa
26 Oct 25 at 7:28 am
Please let me know if you’re looking for a writer for
your site. You have some really good articles and I believe
I would be a good asset. If you ever want to take some of the load off, I’d love
to write some material for your blog in exchange for a
link back to mine. Please blast me an e-mail if interested.
Thanks!
dog dental nearby
26 Oct 25 at 7:29 am
1xbet giri? [url=https://1xbet-16.com]1xbet giri?[/url] .
1xbet_hfOn
26 Oct 25 at 7:30 am
신용카드현금화 – 급전이 필요할 때, 신용카드
한도를 안전하고 간편하게 현금으로 바꿔드립니다.
낮은 수수료, 신용등급 걱정 없이 즉시 입금, 모든 카드사 이용 가능
신용카드현금화
26 Oct 25 at 7:31 am
My brother suggested I would possibly like this website.
He was entirely right. This put up truly made my day. You can not believe simply how so much time I had spent for this info!
Thank you!
Yuma Asami
26 Oct 25 at 7:31 am
Hey I know this is off topic but I was wondering if you knew of any widgets I could add to my
blog that automatically tweet my newest twitter updates.
I’ve been looking for a plug-in like this for quite some time and was hoping maybe you
would have some experience with something like this.
Please let me know if you run into anything. I truly enjoy
reading your blog and I look forward to your new updates.
ankara kürtaj
26 Oct 25 at 7:31 am
mostbet link [url=https://mostbet12031.ru/]https://mostbet12031.ru/[/url]
mostbet_kg_plMa
26 Oct 25 at 7:31 am
кракен
кракен актуальная ссылка
JamesDaync
26 Oct 25 at 7:32 am
Howdy! This is my first visit to your blog! We are a group of volunteers and starting a new project in a
community in the same niche. Your blog provided us useful
information to work on. You have done a outstanding job!
Link Vao 88XX
26 Oct 25 at 7:32 am
Viagra online kopen Nederland: Viagra online kopen Nederland – betrouwbare online apotheek
RandySkync
26 Oct 25 at 7:33 am
1x bet giri? [url=https://1xbet-13.com/]https://1xbet-13.com/[/url] .
1xbet_ddKa
26 Oct 25 at 7:34 am
частная клиника наркологическая [url=https://narkologicheskaya-klinika-23.ru/]https://narkologicheskaya-klinika-23.ru/[/url] .
narkologicheskaya klinika_gbet
26 Oct 25 at 7:35 am
Everything in One Place: https://www.colehardware.com
BryanAlarl
26 Oct 25 at 7:36 am
Wisebusiness.click`s latest blog post
PHP hook, building hooks in your application – Sjoerd Maessen blog at Sjoerd Maessen blog
Wisebusiness.click`s latest blog post
26 Oct 25 at 7:39 am
1xbet yeni giri? [url=www.1xbet-14.com]1xbet yeni giri?[/url] .
1xbet_mdet
26 Oct 25 at 7:39 am
1 x bet [url=https://1xbet-10.com/]https://1xbet-10.com/[/url] .
1xbet_xvea
26 Oct 25 at 7:41 am
ламинат Магазин напольных покрытий – это ваш надежный проводник в мире полов. Здесь представлен широкий ассортимент материалов от ведущих производителей, способных удовлетворить любые запросы и бюджеты. Квалифицированные консультанты помогут вам подобрать оптимальное решение, учитывая особенности помещения, ваши личные предпочтения и финансовые возможности. Помимо самих покрытий, в магазине вы найдете все необходимые сопутствующие товары: подложки, плинтусы, клеи, герметики и средства для ухода за полом. Ваша задача – лишь выбрать, а наша – предоставить все необходимое для создания идеального пола в вашем доме.
SteveVed
26 Oct 25 at 7:42 am
My family members every time say that I am killing my time here at web, except
I know I am getting knowledge daily by reading thes fastidious articles.
ankara kürtaj
26 Oct 25 at 7:45 am
кракен 2025
кракен сайт
JamesDaync
26 Oct 25 at 7:45 am
1xbet g?ncel adres [url=1xbet-16.com]1xbet g?ncel adres[/url] .
1xbet_stOn
26 Oct 25 at 7:45 am
Нужна обработка от клопов для автомобиля, посоветуйте.
обработка от плесени
KennethceM
26 Oct 25 at 7:46 am
поставка медицинского оборудования [url=https://medoborudovanie-postavka.ru/]поставка медицинского оборудования[/url] .
postavka medicinskogo oborydovaniya_wdsn
26 Oct 25 at 7:46 am
Useful and Relevant: https://www.manaolahawaii.com
AlbertBok
26 Oct 25 at 7:48 am
mostbet sitio oficial [url=www.mostbet12031.ru]www.mostbet12031.ru[/url]
mostbet_kg_jqMa
26 Oct 25 at 7:49 am
1 x bet [url=https://1xbet-12.com/]https://1xbet-12.com/[/url] .
1xbet_pmSr
26 Oct 25 at 7:50 am
мостбет скачать приложение на андроид [url=http://mostbet12031.ru/]мостбет скачать приложение на андроид[/url]
mostbet_kg_grMa
26 Oct 25 at 7:51 am
медицинская техника [url=medicinskaya-tehnika.ru]медицинская техника[/url] .
medicinskaya tehnika_atEi
26 Oct 25 at 7:51 am
mostbet скачать бесплатно [url=https://mostbet12031.ru/]https://mostbet12031.ru/[/url]
mostbet_kg_slMa
26 Oct 25 at 7:52 am
1xbet guncel [url=1xbet-13.com]1xbet guncel[/url] .
1xbet_zyKa
26 Oct 25 at 7:53 am
1xbet ?ye ol [url=https://www.1xbet-14.com]https://www.1xbet-14.com[/url] .
1xbet_hjet
26 Oct 25 at 7:54 am
1xbet giri?i [url=https://1xbet-10.com/]https://1xbet-10.com/[/url] .
1xbet_jbea
26 Oct 25 at 7:58 am
вывод из запоя клиника москва [url=http://narkologicheskaya-klinika-23.ru]http://narkologicheskaya-klinika-23.ru[/url] .
narkologicheskaya klinika_rtet
26 Oct 25 at 8:01 am
mostbet com login [url=http://mostbet12031.ru/]http://mostbet12031.ru/[/url]
mostbet_kg_mzMa
26 Oct 25 at 8:02 am
Hello, I desire to subscribe for this weblog to take
newest updates, thus where can i do it please help.
Paito Warna Carolina Day mingguan lengkap
26 Oct 25 at 8:02 am
кракен ios
кракен vk4
JamesDaync
26 Oct 25 at 8:03 am
Обработка вызов санэпидемстанции эффективная, рекомендую.
уничтожение клопов цена
KennethceM
26 Oct 25 at 8:04 am
It is not my first time to go to see this web site,
i am browsing this website dailly and take pleasant facts from
here all the time.
site
26 Oct 25 at 8:05 am
Не парься, полюбасу все уже пришло, зара позвонит курьер и будет тебе счастье, так часто бывает, курьерки коряво работают, ящитаю! купить скорость, кокаин, мефедрон, гашиш Минус оказался только один, и это ожидание, вместо обещанных 3-5 , пришлось ждать больше недели. Не знаю чья эта заслуга отправителя или доставки, но это немного напрягало.
ManuelBrege
26 Oct 25 at 8:05 am
Вызывали санобработка предприятий ночью, приехали быстро!
обработка от клопов частного дома
KennethceM
26 Oct 25 at 8:06 am
1xbet tr giri? [url=http://1xbet-16.com/]http://1xbet-16.com/[/url] .
1xbet_shOn
26 Oct 25 at 8:08 am
1 x bet [url=http://1xbet-14.com]1 x bet[/url] .
1xbet_ovet
26 Oct 25 at 8:09 am
1x giri? [url=http://www.1xbet-12.com]http://www.1xbet-12.com[/url] .
1xbet_kkSr
26 Oct 25 at 8:10 am
1xbet tr [url=www.1xbet-13.com/]1xbet tr[/url] .
1xbet_jeKa
26 Oct 25 at 8:11 am
кракен даркнет маркет
кракен актуальная ссылка
JamesDaync
26 Oct 25 at 8:16 am
1xbet mobi [url=https://1xbet-10.com/]https://1xbet-10.com/[/url] .
1xbet_dgea
26 Oct 25 at 8:16 am
Цена на дератизация цена адекватная, результат супер.
обработка офиса от тараканов
KennethceM
26 Oct 25 at 8:18 am