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=http://www.frei-diplom5.ru]купить диплом о среднем профессиональном образовании с занесением в реестр[/url] .
Diplomi_myPa
25 Oct 25 at 11:12 pm
как купить диплом с занесением в реестр [url=https://frei-diplom1.ru/]как купить диплом с занесением в реестр[/url] .
Diplomi_rcOi
25 Oct 25 at 11:13 pm
1xbet g?ncel [url=1xbet-13.com]1xbet g?ncel[/url] .
1xbet_zqKa
25 Oct 25 at 11:13 pm
купить свидетельство о рождении ссср [url=http://rudik-diplom4.ru/]купить свидетельство о рождении ссср[/url] .
Diplomi_hoOr
25 Oct 25 at 11:15 pm
ставки на спорт кыргызстан [url=https://mostbet12032.ru/]https://mostbet12032.ru/[/url]
mostbet_kg_kzmt
25 Oct 25 at 11:16 pm
диплом купить с занесением в реестр москва [url=www.frei-diplom5.ru/]диплом купить с занесением в реестр москва[/url] .
Diplomi_rcPa
25 Oct 25 at 11:16 pm
купить диплом об окончании техникума в новосибирске [url=www.frei-diplom8.ru]купить диплом об окончании техникума в новосибирске[/url] .
Diplomi_mosr
25 Oct 25 at 11:16 pm
купить диплом в уфе с реестром [url=http://www.frei-diplom4.ru]http://www.frei-diplom4.ru[/url] .
Diplomi_rfOl
25 Oct 25 at 11:17 pm
купить диплом парикмахера [url=http://rudik-diplom8.ru/]купить диплом парикмахера[/url] .
Diplomi_giMt
25 Oct 25 at 11:18 pm
куплю диплом высшего образования [url=http://rudik-diplom3.ru/]куплю диплом высшего образования[/url] .
Diplomi_mvei
25 Oct 25 at 11:18 pm
1xbet yeni giri? [url=https://www.1xbet-12.com]1xbet yeni giri?[/url] .
1xbet_emSr
25 Oct 25 at 11:18 pm
Wow, fantastic blog layout! How long have you been blogging for?
you made blogging look easy. The overall look of your
website is great, as well as the content!
Primo Inviox
25 Oct 25 at 11:18 pm
купить диплом с проведением [url=https://frei-diplom6.ru/]купить диплом с проведением[/url] .
Diplomi_siOl
25 Oct 25 at 11:19 pm
1xbetgiri? [url=https://1xbet-15.com/]1xbet-15.com[/url] .
1xbet_papl
25 Oct 25 at 11:19 pm
At the Playamo casino portal, guests explore an world-class gaming experience with over 3,000 top-quality slot games, table games, and live dealer experiences from renowned software suppliers. No matter if it’s experiencing the cutting-edge online slots, applying strategy at twenty-one, or enjoying real live gaming, the site features experiences for any gaming preference. With a polished, intuitive system, the portal offers fluid performance throughout mobile and desktop, enabling you to play favorite games on your schedule.
Playamo
AlfredLog
25 Oct 25 at 11:20 pm
оч хороший магазин ! купить Мефедрон, Бошки, Марихуану С ним можно работать всегда ровничком всегда адекватность Плюсссс
ManuelBrege
25 Oct 25 at 11:22 pm
мостбет вход на сегодня [url=mostbet12032.ru]mostbet12032.ru[/url]
mostbet_kg_jhmt
25 Oct 25 at 11:22 pm
купить диплом медсестры [url=www.rudik-diplom10.ru/]купить диплом медсестры[/url] .
Diplomi_arSa
25 Oct 25 at 11:22 pm
http://herengezondheid.com/# betrouwbare online apotheek
JamesSlilk
25 Oct 25 at 11:23 pm
Тараканы на кухне? Срочно обработка от клещей!
дезинфекция помещений
KennethceM
25 Oct 25 at 11:23 pm
1xbet lite [url=http://www.1xbet-12.com]http://www.1xbet-12.com[/url] .
1xbet_cjSr
25 Oct 25 at 11:24 pm
What’s up, its nice piece of writing on the topic of media print, we all be aware of media is
a fantastic source of information.
**Paragraph 4: Aesthetic Versatility and Design Options**
Tungsten rings are celebrated for their versatility in design, appealing to a wide range of style preferences.
Available in finishes like high-polish, brushed, or sandblasted, they
offer distinct looks, from sleek and modern to rugged and industrial.
Many tungsten rings feature inlays of materials
such as carbon fiber, abalone shell, or meteorite, adding unique textures and colors.
Black tungsten, achieved through plating or
ionization, provides a bold, contemporary aesthetic, while
classic silver-toned tungsten exudes timeless elegance.
Custom engravings, beveled edges, and faceted designs further
enhance their appeal. This variety allows tungsten rings to cater to both minimalist tastes and those seeking
statement pieces, making them a favorite for wedding bands and fashion jewelry alike.
**Paragraph 5: Durability and Practical Benefits**
One of the standout features of tungsten rings is their unparalleled durability.
Their hardness ensures they resist scratches, dents, and deformation, even under harsh conditions, making them ideal
for individuals with hands-on professions or active hobbies.
Unlike softer metals like gold, which can wear down over time, tungsten maintains its
shape and finish for decades. However, this durability comes with a
caveat: tungsten rings are so hard that they cannot be resized, requiring careful sizing
at purchase. Additionally, while tungsten is nearly indestructible, it can crack under extreme force,
a trait that makes it safer for emergency removal compared to softer metals that bend.
These practical benefits make tungsten rings a reliable choice
for long-term wear.
**Paragraph 6: Affordability Compared to Precious Metals**
Tungsten rings offer significant cost advantages over traditional precious metals like gold, platinum,
or palladium. While gold prices fluctuate based on market demand and purity (e.g., 14K or
18K), tungsten rings are consistently affordable due to the abundance of tungsten and the efficiency of the
manufacturing process. A high-quality tungsten ring can cost as little
as $50 to $200, compared to gold or platinum rings, which often range from $500 to several thousand dollars.
This affordability does not compromise quality, as tungsten’s durability and aesthetic options rival those of more expensive metals.
For couples on a budget or those prioritizing value, tungsten rings provide a cost-effective yet
luxurious option for wedding bands or everyday jewelry.
|rings|mens rings|womens rings|carbide rings|custom rings|engraved rings|tungsten carbide|tungsten wedding rings|tungsten wedding bands|tungsten beveled|tungsten black|tungsten brushed|tungsten celtic|tungsten classic| tungsten gold|
tungsten grooved|tungsten lord of|tungsten mens|tungsten matching|tungsten women|tungsten religious|customized tungsten rings|engraved tungsten rings|tungsten wedding band|tungsten wedding rings|wedding band tungsten|tungsten wedding
bands|wedding bands tungsten|wedding rings tungsten|tungsten wedding ring|tungsten carbide wedding bands|tungsten carbide
wedding rings|wedding ring tungsten|tungsten carbide womens wedding bands|women’s tungsten carbide wedding bands|custom
tungsten wedding band|womens tungsten wedding rings|tungsten for
wedding band}
|rings|mens rings|womens rings|carbide rings|custom rings|engraved rings|tungsten carbide|tungsten wedding rings|tungsten wedding bands|tungsten beveled|tungsten black|tungsten brushed|tungsten celtic|tungsten classic| tungsten gold| tungsten grooved|tungsten lord of|tungsten mens|tungsten matching|tungsten women|tungsten religious|customized tungsten rings|engraved
tungsten rings|tungsten wedding band|tungsten wedding rings|wedding band
tungsten|tungsten wedding bands|wedding bands tungsten|wedding rings tungsten|tungsten wedding ring|tungsten carbide wedding bands|tungsten carbide wedding rings|wedding ring tungsten|tungsten carbide womens wedding bands|women’s tungsten carbide wedding bands|custom tungsten wedding band|womens tungsten wedding rings|tungsten for wedding band}
tungsten wedding
25 Oct 25 at 11:24 pm
купить диплом в заречном [url=www.rudik-diplom3.ru/]купить диплом в заречном[/url] .
Diplomi_xrei
25 Oct 25 at 11:25 pm
kraken РФ
kraken обмен
JamesDaync
25 Oct 25 at 11:25 pm
купить диплом с внесением в реестр [url=http://www.frei-diplom6.ru]купить диплом с внесением в реестр[/url] .
Diplomi_udOl
25 Oct 25 at 11:25 pm
Где дешево дезинфекция цена? Бюджет ограничен.
вывести тараканов
KennethceM
25 Oct 25 at 11:26 pm
1 xbet giri? [url=1xbet-15.com]1xbet-15.com[/url] .
1xbet_dypl
25 Oct 25 at 11:26 pm
кракен vk3
kraken зеркало
JamesDaync
25 Oct 25 at 11:27 pm
1xbet giri? linki [url=https://1xbet-14.com]1xbet giri? linki[/url] .
1xbet_mget
25 Oct 25 at 11:30 pm
купить диплом в твери [url=https://rudik-diplom3.ru/]купить диплом в твери[/url] .
Diplomi_vhei
25 Oct 25 at 11:30 pm
купить диплом в калининграде [url=rudik-diplom8.ru]купить диплом в калининграде[/url] .
Diplomi_fnMt
25 Oct 25 at 11:31 pm
mostbet [url=https://mostbet12031.ru/]mostbet[/url]
mostbet_kg_dvMa
25 Oct 25 at 11:32 pm
1xbet mobil giri? [url=www.1xbet-16.com/]1xbet mobil giri?[/url] .
1xbet_kyOn
25 Oct 25 at 11:32 pm
купить диплом [url=www.rudik-diplom10.ru/]купить диплом[/url] .
Diplomi_hxSa
25 Oct 25 at 11:33 pm
купить оригинальный диплом колледжа [url=https://www.frei-diplom8.ru]https://www.frei-diplom8.ru[/url] .
Diplomi_dksr
25 Oct 25 at 11:33 pm
1xbet turkiye [url=https://1xbet-10.com]https://1xbet-10.com[/url] .
1xbet_pnea
25 Oct 25 at 11:34 pm
Live wetten erkläRung dass gewinner sound
Live wetten erkläRung
25 Oct 25 at 11:35 pm
Hey there terrific website! Does running a blog similar to this require a great deal of work? I’ve absolutely no understanding of computer programming however I had been hoping to start my own blog soon. Anyways, should you have any suggestions or tips for new blog owners please share. I understand this is off subject but I just needed to ask. Many thanks!
вход через зеркало kra42 at
OLaneDrync
25 Oct 25 at 11:36 pm
1xbet spor bahislerinin adresi [url=https://1xbet-15.com/]1xbet spor bahislerinin adresi[/url] .
1xbet_ckpl
25 Oct 25 at 11:36 pm
1x bet giri? [url=http://1xbet-16.com/]1x bet giri?[/url] .
1xbet_xkOn
25 Oct 25 at 11:38 pm
кракен qr код
kraken ссылка
JamesDaync
25 Oct 25 at 11:38 pm
купить диплом в коврове [url=https://rudik-diplom8.ru/]купить диплом в коврове[/url] .
Diplomi_ayMt
25 Oct 25 at 11:38 pm
купить диплом цена [url=https://rudik-diplom11.ru/]купить диплом цена[/url] .
Diplomi_pjMi
25 Oct 25 at 11:39 pm
1xbet giri? 2025 [url=http://www.1xbet-14.com]1xbet giri? 2025[/url] .
1xbet_awet
25 Oct 25 at 11:40 pm
Ресторан чистый после дезинсекция предприятий.
дезинфекция
KennethceM
25 Oct 25 at 11:42 pm
купить диплом в липецке [url=https://rudik-diplom8.ru/]купить диплом в липецке[/url] .
Diplomi_vtMt
25 Oct 25 at 11:43 pm
Вызывали вывести тараканов недавно, результат отличный!
дезинфекция в пищевом производстве
KennethceM
25 Oct 25 at 11:43 pm
купить диплом техникума об окончании [url=frei-diplom8.ru]купить диплом техникума об окончании[/url] .
Diplomi_orsr
25 Oct 25 at 11:43 pm
Ищу обработка от блох в доме с выездом в область.
обработка квартиры от клопов
KennethceM
25 Oct 25 at 11:45 pm
1xbet yeni giri? [url=1xbet-12.com]1xbet yeni giri?[/url] .
1xbet_rdSr
25 Oct 25 at 11:45 pm