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://educ-ua19.ru/]http://educ-ua19.ru/[/url] .
Diplomi_xuml
12 Sep 25 at 11:04 pm
Je suis totalement ebloui par RubyVegas Casino, ca degage une ambiance de jeu aussi eclatante qu’une gemme. Il y a une cascade de jeux de casino captivants, offrant des sessions de casino en direct qui brillent comme des gemmes. L’assistance du casino est chaleureuse et irreprochable, joignable par chat ou email. Les gains du casino arrivent a une vitesse fulgurante, quand meme j’aimerais plus de promotions de casino qui eblouissent. Pour resumer, RubyVegas Casino est une pepite pour les fans de casino pour ceux qui cherchent l’adrenaline scintillante du casino ! Par ailleurs la navigation du casino est intuitive comme une gemme taillee, facilite une experience de casino scintillante.
glitterybadger9zef
12 Sep 25 at 11:04 pm
Estou pirando com RioPlay Casino, tem uma vibe de jogo tao animada quanto um desfile na Sapucai. Os titulos do cassino sao uma explosao de cores e sons, com slots de cassino tematicos de festa. O suporte do cassino ta sempre na ativa 24/7, respondendo mais rapido que um batuque. As transacoes do cassino sao simples como um passo de samba, mas queria mais promocoes de cassino que botam pra quebrar. Em resumo, RioPlay Casino vale demais sambar nesse cassino para os apaixonados por slots modernos de cassino! Alem disso a plataforma do cassino brilha com um visual que e puro samba, o que torna cada sessao de cassino ainda mais animada.
rioplay games roblox lite|
wildpineapplegator3zef
12 Sep 25 at 11:04 pm
купить диплом о высшем образовании с занесением в реестр [url=https://educ-ua15.ru]https://educ-ua15.ru[/url] .
Diplomi_pimi
12 Sep 25 at 11:08 pm
Highly energetic post, I liked that a lot. Will there be a part 2?
QuantoRovex
12 Sep 25 at 11:08 pm
вывод из запоя
vivod-iz-zapoya-orenburg008.ru
лечение запоя
izzapoyaorenburgNeT
12 Sep 25 at 11:08 pm
Puzzles online https://castro.fm/podcast/110ee563-2d6f-4d0d-a4f5-b3048673c2a5 play for free in assembling pictures of any complexity. Thousands of options: classic, children’s, 3D and thematic. Convenient interface, saving progress and new puzzles every day.
puzzlefree-450
12 Sep 25 at 11:09 pm
Просьба не флудить. Руж тем более не развивать больные фантазии.
https://www.divephotoguide.com/user/jagiiguof
в подписи ТС смотри контакты)
Jamesvok
12 Sep 25 at 11:11 pm
Даже если кажется, что «пройдёт само», при запойных состояниях осложнения нарастают быстро. Перед списком отметим логику: показания к инфузионной терапии определяет врач по совокупности симптомов, хронических заболеваний и текущих показателей. Ниже — типичные ситуации, при которых капельница даёт предсказуемый клинический эффект и снижает риски.
Детальнее – https://kapelnica-ot-zapoya-vidnoe7.ru/kapelnica-ot-zapoya-kruglosutochno-v-vidnom/
EugeneSoype
12 Sep 25 at 11:16 pm
kraken onion kraken onion, kraken onion ссылка, kraken onion зеркала, kraken рабочая ссылка onion, сайт kraken onion, kraken darknet, kraken darknet market, kraken darknet ссылка, сайт kraken darknet, kraken актуальные ссылки, кракен ссылка kraken, kraken официальные ссылки, kraken ссылка тор, kraken ссылка зеркало, kraken ссылка на сайт, kraken онион, kraken онион тор, кракен онион, кракен онион тор, кракен онион зеркало, кракен даркнет маркет, кракен darknet, кракен onion, кракен ссылка onion, кракен onion сайт, kra ссылка, kraken сайт, kraken актуальные ссылки, kraken зеркало, kraken ссылка зеркало, kraken зеркало рабочее, актуальные зеркала kraken, kraken сайт зеркала, kraken маркетплейс зеркало, кракен ссылка, кракен даркнет
RichardPep
12 Sep 25 at 11:17 pm
Капельница для восстановления после алкогольного отравления – это работающим средством для восстановления организма после алкогольного отравления. В владимире медицинские услуги в виде вливание глюкозы и электролитов позволяет снять симптомы похмелья, такие как головная боль, тошнота и слабость. Медицинские учреждения в владимире предлагают услуги с использованием энтеросгеля с целью детоксикации. Гидратация организма также играет важную роль в процессе восстановления. Важно помнить о необходимости консультации врача прежде чем начинать лечение. Для получения дополнительной информации посетите сайт vivod-iz-zapoya-vladimir012.ru.
zapojvladimirNeT
12 Sep 25 at 11:17 pm
актуальные зеркала kraken kraken onion, kraken onion ссылка, kraken onion зеркала, kraken рабочая ссылка onion, сайт kraken onion, kraken darknet, kraken darknet market, kraken darknet ссылка, сайт kraken darknet, kraken актуальные ссылки, кракен ссылка kraken, kraken официальные ссылки, kraken ссылка тор, kraken ссылка зеркало, kraken ссылка на сайт, kraken онион, kraken онион тор, кракен онион, кракен онион тор, кракен онион зеркало, кракен даркнет маркет, кракен darknet, кракен onion, кракен ссылка onion, кракен onion сайт, kra ссылка, kraken сайт, kraken актуальные ссылки, kraken зеркало, kraken ссылка зеркало, kraken зеркало рабочее, актуальные зеркала kraken, kraken сайт зеркала, kraken маркетплейс зеркало, кракен ссылка, кракен даркнет
RichardPep
12 Sep 25 at 11:18 pm
Medicament information. Brand names.
how to buy cipro without insurance
Some about medicines. Read here.
how to buy cipro without insurance
12 Sep 25 at 11:19 pm
If you want to get much from this piece of writing then you have to apply these techniques to your won web site.
Oryvian Platform
12 Sep 25 at 11:20 pm
https://www.azorelle.com/2025/08/03/vlezte-v-verde-casino-free-spins-sshhnostta-na/
JeffreyThota
12 Sep 25 at 11:20 pm
купить диплом с реестром [url=http://educ-ua11.ru]купить диплом с реестром[/url] .
Diplomi_jvPi
12 Sep 25 at 11:27 pm
Pills information for patients. Brand names.
cephalexin exel
All information about medication. Read now.
cephalexin exel
12 Sep 25 at 11:28 pm
https://bas-ir.com/dobre-doshli-v-verde-casino-25-srceto-na/
JeffreyThota
12 Sep 25 at 11:29 pm
kraken зеркало kraken onion, kraken onion ссылка, kraken onion зеркала, kraken рабочая ссылка onion, сайт kraken onion, kraken darknet, kraken darknet market, kraken darknet ссылка, сайт kraken darknet, kraken актуальные ссылки, кракен ссылка kraken, kraken официальные ссылки, kraken ссылка тор, kraken ссылка зеркало, kraken ссылка на сайт, kraken онион, kraken онион тор, кракен онион, кракен онион тор, кракен онион зеркало, кракен даркнет маркет, кракен darknet, кракен onion, кракен ссылка onion, кракен onion сайт, kra ссылка, kraken сайт, kraken актуальные ссылки, kraken зеркало, kraken ссылка зеркало, kraken зеркало рабочее, актуальные зеркала kraken, kraken сайт зеркала, kraken маркетплейс зеркало, кракен ссылка, кракен даркнет
RichardPep
12 Sep 25 at 11:34 pm
Тут ровно братаны,берем и не паримся,качеставо вышка!)
https://igli.me/dfpk9537
Ну да ,я уже посылку с 15числа жду всё дождаться не могу .
Robertheini
12 Sep 25 at 11:35 pm
мостбет казино зеркало [url=mostbet12007.ru]mostbet12007.ru[/url]
mostbet_oept
12 Sep 25 at 11:35 pm
Мы предлагаем документы ВУЗов, расположенных на территории всей Российской Федерации. Купить диплом ВУЗа:
[url=http://joblinksolution.org/employer/diplomiki/]купить аттестат 11[/url]
Diplomi_xuPn
12 Sep 25 at 11:36 pm
написать курсовую онлайн курсовая купить москва
kursovaya-rabota-187
12 Sep 25 at 11:36 pm
https://russpain.com/
Roberttow
12 Sep 25 at 11:37 pm
eSIM Europe
Europe SIM Card
12 Sep 25 at 11:37 pm
«Как отмечает врач-нарколог Павел Викторович Зайцев, «эффективность терапии во многом зависит от своевременного обращения, поэтому откладывать визит в клинику опасно»».
Изучить вопрос глубже – [url=https://narkologicheskaya-klinika-sankt-peterburg14.ru/]www.domen.ru[/url]
Romanronse
12 Sep 25 at 11:43 pm
Puzzles online https://stackexchange.com/users/43844246/ivan-jarkov play for free in assembling pictures of any complexity. Thousands of options: classic, children’s, 3D and thematic. Convenient interface, saving progress and new puzzles every day.
puzzlefree-84
12 Sep 25 at 11:45 pm
В первые часы важно не «залить» пациента растворами, а корректно подобрать темп и состав с учётом возраста, массы тела, артериального давления, лекарственного фона (антигипертензивные, сахароснижающие, антиаритмические препараты) и переносимости. Именно поэтому мы не отдаём лечение на откуп шаблонам — каждая схема конструируется врачом на месте, а эффективность оценивается по понятным метрикам.
Подробнее тут – https://vyvod-iz-zapoya-v-ryazani14.ru
Jameszinee
12 Sep 25 at 11:46 pm
купить диплом бакалавра дешево [url=http://www.educ-ua19.ru]купить диплом бакалавра дешево[/url] .
Diplomi_bjml
12 Sep 25 at 11:47 pm
Puzzles online https://stackexchange.com/users/43844246/ivan-jarkov play for free in assembling pictures of any complexity. Thousands of options: classic, children’s, 3D and thematic. Convenient interface, saving progress and new puzzles every day.
puzzlefree-948
12 Sep 25 at 11:48 pm
курсовой проект купить цена написание курсовой на заказ цена
kursovaya-rabota-974
12 Sep 25 at 11:49 pm
Hello, i think that i saw you visited my weblog thus
i came to “return the favor”.I am trying to find things to enhance my web site!I suppose
its ok to use some of your ideas!!
corporate directory singapore
12 Sep 25 at 11:49 pm
Puzzles online https://winbuzzer.com/2025/09/06/why-playing-puzzles-online-is-better-than-offline-7-unexpected-reasons-xcxwgp/ play for free in assembling pictures of any complexity. Thousands of options: classic, children’s, 3D and thematic. Convenient interface, saving progress and new puzzles every day.
puzzlefree-942
12 Sep 25 at 11:49 pm
It’s very simple to find out any topic on net as compared to books, as I found this paragraph at this site.
Royal x casino
12 Sep 25 at 11:49 pm
купить диплом занесением реестр [url=http://www.educ-ua15.ru]купить диплом занесением реестр[/url] .
Diplomi_szmi
12 Sep 25 at 11:51 pm
Listen up, Singapore folks, mathematics іѕ liҝely thе highly essential primary topic, promoting imagination tһrough ρroblem-solving
to creative jobs.
Nanyang Junior College champions multilingual excellence, mixing
cultural heritage ѡith contemporary education to
support positive global citizens. Advanced centers
support strong programs іn STEM, arts, and humanities, promoting innovation ɑnd creativity.
Trainees grow іn a vibrant neighborhood ԝith opportunities fοr leadership
and global exchanges. The college’ѕ emphasis on worths аnd resilience
constructs character tߋgether with academic prowess. Graduates master tоp
institutions, continuing a tradition οf ahievement and cultural gratitude.
Ѕt. Andrew’s Junior College ԝelcomes Anglican values tօ promote holistic development, cultivating
principled people ѡith robust character traits tһrough a mix of spiritual guidance, scholastic pursuit, ɑnd neighborhood involvement
іn a warm and inclusive environment. Ƭhe college’s modern amenities,
including interactive classrooms, sports complexes, аnd
imaginative arts studios, facilitate quality tһroughout scholastic disciplines, sports programs tһat emphasize fitness аnd fair play, and creatkve ventures tһɑt encourage self-expression аnd
development. Neighborhood service efforts, ѕuch as volunteer
collaborations wіth regional organizations ɑnd outreach
tasks, impart compassion, social responsibility, аnd
a sense of function, improving students’ academic journeys.
А varied variety օf ϲo-curricular activities,
fгom argument societies tо musical ensembles, promotes teamwork, management skills, аnd personal
discovery, permitting еverʏ trainee to shine in theiг
selected locations. Alumni оf St. Andrew’s Junior College regularly ƅecome ethical, resilient
leaders ѡһo make meaningful contributions to society,
reflecting tһe institution’s profound еffect
on developing ԝell-rounded, vaⅼue-driven people.
Mums аnd Dads, fearful of losing style activated lah, robust
primary maths esults tο superior science understanding plus tech aspirations.
Aiyo, ԝithout robust mathematics ɑt Junior College, regaгdless toρ school youngsters miɡht
stumble іn next-level equations, ѕo cultivate it immediately leh.
Do not play play lah, pair а excellent Junior College alongside math excellence іn ordеr to assure elevated
A Levels scores рlus effortless transitions.
Mums ɑnd Dads, dread the gap hor, math base гemains vital in Junior College іn understanding
figures, crucial ѡithin current digital market.
Goodness, no matter іf school proves һigh-end, math acts like
thе decisive subject to cultivates assurance іn figures.
Math at Η2 level in A-levels is tough, but mastering it proves you’re
ready for uni challenges.
Oh no, primary maths teaches practical implementations including money management, tһuѕ make sure yoᥙr
youngster gets it right starting ʏoung age.
Feel free to surf tο my blog post; Temasek Junior College
Temasek Junior College
12 Sep 25 at 11:53 pm
писать курсовые за деньги курсовые на заказ москва
kursovaya-rabota-539
12 Sep 25 at 11:57 pm
1win букмекерская контора официальный сайт вход [url=http://1win12005.ru/]http://1win12005.ru/[/url]
1win_saol
13 Sep 25 at 12:00 am
https://blogfreely.net/meghadldhn/mitos-sobre-limpiezas-rpidas-del-cuerpo-que-debes-conocer
Gestionar un control sorpresa puede ser complicado. Por eso, ahora tienes una formula avanzada con respaldo internacional.
Su mezcla potente combina carbohidratos, lo que prepara tu organismo y oculta temporalmente los trazas de sustancias. El resultado: un analisis equilibrado, lista para entregar tranquilidad.
Lo mas notable es su capacidad inmediata de respuesta. A diferencia de otros productos, no promete resultados permanentes, sino una estrategia de emergencia que funciona cuando lo necesitas.
Miles de postulantes ya han comprobado su rapidez. Testimonios reales mencionan paquetes 100% confidenciales.
Si necesitas asegurar tu resultado, esta alternativa te ofrece respaldo.
JuniorShido
13 Sep 25 at 12:00 am
кондиционеры [url=http://kondicioner-obninsk-1.ru]кондиционеры[/url] .
kondicioneri s ystanovkoi_yomi
13 Sep 25 at 12:01 am
мостбет казино скачать [url=mostbet12008.ru]мостбет казино скачать[/url]
mostbet_nder
13 Sep 25 at 12:01 am
Wonderful blog! Do you have any tips for aspiring writers?
I’m hoping to start my own site soon but I’m a little lost
on everything. Would you propose starting with a free platform like
Wordpress or go for a paid option? There are so
many options out there that I’m completely confused ..
Any ideas? Appreciate it!
pharmaceutical industry
13 Sep 25 at 12:02 am
I like the helpful information you provide in your articles.
I’ll bookmark your blog and check again here frequently.
I’m quite sure I’ll learn a lot of new stuff right here!
Good luck for the next!
Maria Ozawa
13 Sep 25 at 12:04 am
Здравствуйте, форумчане!
Сегодня хочу обсудить тему,
которая давно меня интересует — Что посмотреть в Китае.
Этот огромный и разнообразный край манит
своей насыщенной культурой, древней мудростью и потрясающими пейзажами, поэтому решил поделиться своими впечатлениями и рассмотреть
лучшие места для путешествий.
Если рассуждать о основных достопримечательностях, нельзя не
назвать Великую китайскую стену — поистине поражающее
сооружение, которое поражает своей масштабом и
историей. Также стоит посмотреть на старинный
город Пекин со своей удивительной архитектурой и дворцами, а для ценителей природы рекомендуются живописные горы Хуаншань, где восходы солнца создают впечатляющие сцены.
[b]Культура[/b] и [b]природа[/b] здесь гармонично
переплетаются, что превращает путешествие по
Китаю по-настоящему уникальным
опытом.
В результате, Китай — это
страна, где каждый обнаружит что-то
особенное, будь то история, природа или современность.
А как вы думаете? Какие места в Китае произвели на вас максимальное впечатление, и
что бы вы рекомендовали обязательно посмотреть тем, кто только планирует поездку?
Будет любопытно услышать ваше мнение!
37.221.202.29
37.221.202.29
13 Sep 25 at 12:09 am
купить диплом магистра [url=https://educ-ua19.ru]купить диплом магистра[/url] .
Diplomi_arml
13 Sep 25 at 12:09 am
Недавно установили [url=https://razvitieagro.ru/shhelevye-poly-lagi-stekloplastikovye/]щелевые полы для свиней купить[/url]. Честно говоря, изменения огромные: чистота держится дольше, запахов меньше, животные содержатся в лучших условиях. Такие полы облегчают работу и экономят время. Для фермеров это решение, которое сразу даёт результат.
RavzenaProrp
13 Sep 25 at 12:09 am
http://truenorthpharm.com/# buy prescription drugs from canada cheap
JeremyBip
13 Sep 25 at 12:10 am
SaludFrontera: buying prescriptions in mexico – SaludFrontera
Teddyroowl
13 Sep 25 at 12:10 am
TrueNorth Pharm: canadian pharmacy cheap – TrueNorth Pharm
Charlesdyelm
13 Sep 25 at 12:10 am
https://impossible-studio.ghost.io/kak-vybrat-luchshii-vpn-siervis-podrobnoie-rukovodstvo/ Новый лонгрид про Youtuber VPN! Узнайте, как смотреть YouTube и другие платформы без лагов и блокировок. Подключайте до 5 устройств на одной подписке, тестируйте сервис бесплатно 3 дня и платите всего 290? в первый месяц вместо 2000? у конкурентов. Серверы в Европе — ваши данные защищены от российских властей.
Kevintow
13 Sep 25 at 12:11 am