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=www.educ-ua4.ru/]купить диплом института[/url] .
Diplomi_qxPl
2 Sep 25 at 10:54 pm
Турагентство в Тюмени Акуна Матата Горящие туры. Поиск туров на сайте https://akuna-matata72.ru/ от всех надёжных туроператоров. Мы подберем Вам отдых по выгодным ценам. Туры в Турцию, Египет, Таиланд, ОАЭ, Китай (остров Хайнань), Вьетнам, Индонезию (остров Бали), Мальдивы, остров Маврикий, Шри-Ланка, Доминикану, Кубу и в другие страны. Туры из Тюмени и других городов. Мы расскажем Вам не только о пляжах, но и об особенностях безопасного и интересного отдыха в той или иной стране, про места, где лучше посетить экскурсии и любимые кафе.
Hepideshok
2 Sep 25 at 10:55 pm
https://vk.com/3dplabs
CoreyThype
2 Sep 25 at 10:57 pm
I read this post completely on the topic of the difference
of newest and previous technologies, it’s remarkable article.
кт томография
2 Sep 25 at 10:58 pm
Казино Pinco слот Anaki Skywalker
Jorgegrect
2 Sep 25 at 11:06 pm
кашпо под цветы напольные [url=https://www.kashpo-napolnoe-krasnodar.ru]кашпо под цветы напольные[/url] .
kashpo napolnoe _toel
2 Sep 25 at 11:07 pm
Ищете медицинскую справку удалённо без трудностей? На [url=https://novomed-cardio.ru]https://novomed-cardio.ru[/url] можно получить справку 086/у или 027/у в течение часа с быстрой доставкой. Надёжно, оперативно и анонимно – переходите на сайт.
Spravkihkq
2 Sep 25 at 11:08 pm
Ищете действенное решение против гепатита С? Велакаст — оригинальная комбинация софосбувира и велпатасвира с гарантией подлинности и быстрой доставкой по России. Ищете велакаст для лечения гепатита С? Velakast.com.ru Поможем подобрать оптимальный курс и ответим на все вопросы, чтобы вы стартовали терапию без задержек. Оформите консультацию уже сегодня и получите прозрачные условия покупки — шаг к вашему здоровью.
difacaViemn
2 Sep 25 at 11:09 pm
mostbet app [url=https://mostbet4121.ru]https://mostbet4121.ru[/url]
mostbet_ljst
2 Sep 25 at 11:10 pm
Ran into a captivating read give it a go http://bs.listbb.ru/posting.php?mode=post&f=3&sid=1986a670c9a36a7e31e2aea92b32f873
DavidNak
2 Sep 25 at 11:12 pm
мостбет личный кабинет [url=https://mostbet4123.ru]https://mostbet4123.ru[/url]
mostbet_tbKa
2 Sep 25 at 11:15 pm
Казино Joycasino слот Alchemy Ways
Marvinawasp
2 Sep 25 at 11:15 pm
Hi there, after reading this awesome article i am
as well cheerful to share my familiarity here with colleagues.
Immediate X AI
2 Sep 25 at 11:15 pm
best online casinos
Darwinlix
2 Sep 25 at 11:20 pm
кракен онион тор
RichardPep
2 Sep 25 at 11:20 pm
: buy antibiotics online – buy antibiotics for tooth infection
Frankelova
2 Sep 25 at 11:22 pm
We absolutely love your blog and find many of your post’s to be just what I’m looking for.
Would you offer guest writers to write content for you personally?
I wouldn’t mind publishing a post or elaborating on a lot
of the subjects you write concerning here. Again, awesome blog!
Energy-efficient air conditioning Houston
2 Sep 25 at 11:29 pm
mostbet бетгеймс [url=https://mostbet4120.ru]mostbet бетгеймс[/url]
mostbet_wqpr
2 Sep 25 at 11:31 pm
Wealth Ancestry Prayer seems really interesting for people who
want to connect with their roots while also inviting more abundance into their lives.
I like that it focuses on spiritual alignment and positive energy, rather than just
material gain. It feels like a meaningful practice for those who believe in combining faith, heritage, and prosperity.
Wealth Ancestry Prayer
2 Sep 25 at 11:33 pm
mosbet [url=https://mostbet4121.ru]mosbet[/url]
mostbet_oust
2 Sep 25 at 11:34 pm
A person necessarily lend a hand to make significantly articles I might
state. That is the first time I frequented your web page and
so far? I amazed with the analysis you made to create this actual publish amazing.
Great process!
Agueda
2 Sep 25 at 11:34 pm
https://dozor-ekb.ru
Garthtoild
2 Sep 25 at 11:37 pm
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.
5MB
2 Sep 25 at 11:38 pm
Мы предлагаем документы институтов, расположенных на территории всей Российской Федерации. Купить диплом о высшем образовании:
[url=http://hellotrek.com/kupit-diplom-s-zaneseniem-v-reestr-197/]где купить аттестат 11 классов в нижнем новгороде[/url]
Diplomi_lwPn
2 Sep 25 at 11:40 pm
Hey are using WordPress for your blog platform?
I’m new to the blog world but I’m trying to get started and set up my own. Do you need any coding knowledge to make your own blog?
Any help would be really appreciated!
side scroller
2 Sep 25 at 11:42 pm
В Наркологической клинике “Новая жизнь” работает команда высококвалифицированных врачей, обладающих значительным опытом в области наркологии и психиатрии. Все специалисты имеют профильное образование и постоянно повышают свою квалификацию, что позволяет им быть в курсе последних достижений в лечении зависимостей.
Получить больше информации – http://нарко-специалист.рф/vivod-iz-zapoya-anonimno-v-Ekaterinburge/
CharlesFlerb
2 Sep 25 at 11:43 pm
Нужна справку от врача онлайн без лишних хлопот? На [url=https://novomed-cardio.ru]https://novomed-cardio.ru[/url] можно заказать справку формы 086/у или справку 027/у в тот же день с курьерской доставкой. Надёжно, оперативно и без разглашения – узнайте подробности на сайте.
Spravkixqd
2 Sep 25 at 11:44 pm
Drug information leaflet. Short-Term Effects.
exploring the benefits and uses of diclofenac na 75 mg ec tablets
Some news about medicines. Get here.
exploring the benefits and uses of diclofenac na 75 mg ec tablets
2 Sep 25 at 11:48 pm
kraken рабочая ссылка onion
RichardPep
2 Sep 25 at 11:48 pm
Таким образом, мы создаём систему поддержки, позволяющую каждому пациенту успешно справляться с зависимостью и вернуться к полноценной жизни.
Подробнее – [url=https://alko-lechebnica.ru/]вывод из запоя на дому цена[/url]
Georgecem
2 Sep 25 at 11:49 pm
кракен ссылка kraken
RichardPep
2 Sep 25 at 11:50 pm
мостбет зеркало [url=https://mostbet4120.ru]https://mostbet4120.ru[/url]
mostbet_tapr
2 Sep 25 at 11:53 pm
Покупки с VPN MEFEDRON MEF SHISHK1 ALFA_PVP МСК
Jessiereimb
2 Sep 25 at 11:56 pm
интернет по адресу краснодар
inernetvkvartiru-krasnodar004.ru
интернет провайдеры по адресу краснодар
inernetkrdelini
2 Sep 25 at 11:56 pm
член сломался, секс-кукла, продажа секс-игрушек, राजा छह, राजा ने पैर फैलाकर, प्लर राजा, ৰাজ্যসমূহৰ ৰজা, গুৰুত্বপূৰ্ণ সঁজুলি বিক্ৰী কৰা
ৰাজ্যসমূহৰ ৰজা
2 Sep 25 at 11:58 pm
download 888starz on Android phone https://www.pgyer.com/apk/en/apk/app.starz.online
888Starzpgyeren
3 Sep 25 at 12:03 am
mostbet казино [url=www.mostbet4123.ru]mostbet казино[/url]
mostbet_mnKa
3 Sep 25 at 12:04 am
kraken darknet ссылка
RichardPep
3 Sep 25 at 12:04 am
How to Take a Screenshot
ArchieKar
3 Sep 25 at 12:05 am
Why people still make use of to read news papers when in this technological world everything is available on net?
https://infobus.com.ua/yak-vybraty-sklo-na-faru-dlya-riznykh-umov-eksplua.html
Timsothydet
3 Sep 25 at 12:07 am
mosbet [url=https://mostbet4124.ru/]https://mostbet4124.ru/[/url]
mostbet_ixsr
3 Sep 25 at 12:08 am
Even during his days off, Raul Morales gets spotted by fans. On a recent visit to Universal Studios Hollywood, Morales, owner of Taqueria Vista Hermosa in Los Angeles, was waiting in line when he heard shouting.
“People called out ‘Chef Al Pastor! Chef Al Pastor!’” Morales said, laughing. Morales, who was born in Mexico City, came by the nickname through decades of hard work.
[url=https://trip-scan39.org]tripscan[/url]
He’s the third generation of his family to make al pastor tacos, their fresh tortillas filled with richly seasoned pork shaved from a rotating vertical spit.
“My recipe is very special, and very old,” he said.
Yet while Morales’ family recipes go back generations, and similar spit-roasted meats like shawarma and doner have been around for hundreds of years, his tacos represent a kind of cuisine that’s as contemporary and international as it is ancient and traditional. When you thread meat onto a spinning spit to roast it, it turns out, it doesn’t stay in one place for long.
https://trip-scan39.org
tripscan войти
‘Any place you have a pointy stick or a sword’
Roasting meat on a spit or stick is likely among humans’ most ancient cooking techniques, says food historian Ken Albala, a professor of history at the University of the Pacific.
Feasts of spit-roasted meat appear in the Homeric epics The Iliad and The Odyssey, writes Susan Sherratt, emeritus professor of East Mediterranean archaeology at the University of Sheffield, in the journal Hesperia.
Iron spits that might have been used for roasting appear in the Aegean starting in the 10th century BCE. Such spits have been unearthed in tombs associated with male warriors, Sherratt writes, noting that roasting meat may have been a practice linked to male bonding and masculinity.
“I think the reason that it’s associated with men is partly because of hunting, and the tools, or weapons, that replicated what you would do in war,” Albala said. “When you celebrated a victory, you would go out and sacrifice an animal to the gods, which would basically be like a big barbecue.”
Roasting meat is not as simple as dangling a hunk of meat over the flames. When roasting, meat is not cooked directly on top of the heat source, Albala says, but beside it, which can generate richer flavors.
“Any place you have a pointy stick or a sword, people are going to figure out very quickly … if you cook with it off to the side of the fire, it’s going to taste much more interesting,” Albala said.
JustinCek
3 Sep 25 at 12:10 am
мостбет мобильная версия [url=mostbet4127.ru]mostbet4127.ru[/url]
mostbet_kg_ncmr
3 Sep 25 at 12:15 am
букмекерская контора mostbet [url=www.mostbet4124.ru]www.mostbet4124.ru[/url]
mostbet_zisr
3 Sep 25 at 12:15 am
Без медицинского вмешательства состояние быстро прогрессирует: появляется тремор, резкие скачки давления, судороги, бессонница, галлюцинации. Чем дольше затягивать с лечением, тем выше риск развития алкогольного делирия (белой горячки), острого панкреатита, инсульта или инфаркта. Особенно опасно оставлять человека одного в квартире в период ломки — даже банальный приём воды может закончиться удушьем или потерей сознания. Именно поэтому капельница должна быть проведена как можно раньше, под наблюдением специалистов.
Детальнее – http://kapelnica-ot-zapoya-moskva2.ru/
ElbertLooda
3 Sep 25 at 12:18 am
https://www.spreaker.com/podcast/conaldmscu–6718997
Did you know that in this year, only 2,043 companies earned a spot in the Top Countertop Contractors Ranking out of over ten thousand evaluated? That’s because at we don’t just accept anyone.
Our ranking is transparent, constantly refreshed, and built on more than 20 criteria. These include reviews from Google, Yelp, and other platforms, pricing, responsiveness, and project quality. On top of that, we conduct thousands of phone calls and over two thousand estimate requests through our mystery shopper program.
The result is a standard that benefits both homeowners and installation companies. Homeowners get a proven way to choose contractors, while listed companies gain credibility, online authority, and even more inquiries.
The Top 500 Awards spotlight categories like Established Leaders, Emerging Leaders, and Budget-Friendly Pros. Winning one of these honors means a company has achieved rare credibility in the industry.
If you’re ready to hire a countertop contractor—or your company wants to earn recognition—this site is where quality meets growth.
JuniorShido
3 Sep 25 at 12:18 am
мостбет вход сегодня [url=http://mostbet4123.ru]http://mostbet4123.ru[/url]
mostbet_tuKa
3 Sep 25 at 12:19 am
J’apprecie enormement Casino Action, ca procure une energie de jeu irresistible. La selection de jeux est impressionnante avec plus de 1000 titres, proposant des jeux de table classiques comme le blackjack et la roulette. Les agents sont professionnels et toujours prets a aider, joignable a toute heure. Les gains arrivent en un temps record, bien que le bonus de bienvenue jusqu’a 1250 € pourrait etre plus frequent. Dans l’ensemble, Casino Action est une plateforme d’exception pour les adeptes de sensations fortes ! De plus le design est visuellement attrayant, ce qui amplifie le plaisir de jouer.
casino action kokemuksia|
Francismary8zef
3 Sep 25 at 12:19 am
https://dosaaf45.ru
Garthtoild
3 Sep 25 at 12:20 am
где купить аттестаты за 11 класс в нижнем тагиле [url=www.arus-diplom24.ru/]где купить аттестаты за 11 класс в нижнем тагиле[/url] .
Diplomi_dwsa
3 Sep 25 at 12:22 am