PHP 8.2: Co je nového?
Nová verze PHP je již za rohem. O jakých nových implementacích byste měli vědět? Podívejte se na tento článek a zjistěte to!
Přečtěte si první díl seriálu PHP věnovaný komunikaci mikroslužeb ve frameworku Symfony a nejoblíbenějšímu způsobu - komunikaci AMQP pomocí RabbitMQ.
Moderní architektura aplikací donutila vývojáře změnit způsob uvažování o komunikaci mezi různými komponentami IT systémů. Kdysi byla věc jednodušší - většina systémů byla vytvářena jako monolitické struktury propojené navzájem sítí vazeb obchodní logiky. Udržování takových závislostí v PHP projekt byla pro Vývojáři PHPa rostoucí popularita SaaS řešení a obrovský nárůst popularity cloud služby způsobily, že dnes stále častěji slyšíme o mikroslužby a modularita aplikací.
Jak můžeme vytvořením nezávislých mikroslužeb dosáhnout toho, aby si mezi sebou vyměňovaly informace?
Tento článek je prvním ze série příspěvků o komunikace mikroslužeb v Symfony a pokrývá nejoblíbenější způsob - komunikaci AMQP pomocí RabbitMQ.
Vytvoření dvou nezávislých aplikací a dosažení komunikace mezi nimi pouze pomocí sběrnice Message Bus.
Máme dvě pomyslné nezávislé aplikace:
* app1: který zasílá zaměstnancům e-mailová a SMS oznámení
* app2: který umožňuje řídit práci zaměstnanců a přidělovat jim úkoly.
Chceme vytvořit moderní a jednoduchý systém, v němž bude přidělování práce zaměstnanci v rámci app2 odešle zákazníkovi oznámení pomocí app1. Navzdory zdání je to velmi jednoduché!
Pro účely tohoto článku použijeme nejnovější verzi Symfony (v době psaní článku verze 6.1) a nejnovější verzi PHP (8.1). V několika velmi jednoduchých krocích vytvoříme funkční lokální Docker prostředí se dvěma mikroslužbami. Vše, co potřebujete, je:
* funkční počítač,
* nainstalovaný Docker + Prostředí Docker Compose
* a místně nakonfigurovanou Symfony CLI a nějaký volný čas.
Využijeme možnosti nástroje Docker jako nástroje pro virtualizaci a kontejnerizaci aplikací. Začneme vytvořením adresářového stromu, rámce pro dva Aplikace Symfony, a popsat infrastrukturu našich prostředí pomocí docker-compose.yml soubor.
cd ~
mkdir microservices-in-symfony
cd microservices-in-symfony
symfony new app1
symfony new app2
touch docker-compose.yml
Vytvořili jsme dva adresáře pro dvě samostatné aplikace Symfony a vytvořili prázdný adresář docker-compose.yml spustit naše prostředí.
Přidejme následující sekce do docker-compose.yml file:
verze: '3.8'
služby:
app1:
containername: app1
build: app1/.
restart: při selhání
envfile: app1/.env
environment:
APPNAME: app1
tty: true
stdinopen: true
app2:
containername: app2
build: app2/.
restart: při selhání
envfile: app2/.env
environment:
APPNAME: app2
tty: true
stdinopen: true
rabbitmq:
containername: rabbitmq
image: rabbitmq:management
ports:
- 15672:15672
- 5672:5672
prostředí:
- RABBITMQDEFAULTUSER=user
- RABBITMQDEFAULT_PASS=password
Zdroj: kód k dispozici přímo: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml
Ale počkejte, co se tu stalo? Těm, kdo neznají Docker, se výše uvedený konfigurační soubor může zdát záhadný, jeho účel je však velmi jednoduchý. Pomocí nástroje Docker Compose vytváříme tři "služby":
Pro správnou funkci stále potřebujeme Soubor Dockerfile soubory, které jsou zdrojem pro vytváření obrazů. Pojďme je tedy vytvořit:
touch app1/Dockerfile
touch app2/Dockerfile
Oba soubory mají naprosto stejnou strukturu a vypadají následovně:
Z php:8.1
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY . /app/
WORKDIR /app/
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
Spustit chmod +x /usr/local/bin/install-php-extensions && sync &&
install-php-extensions amqp
Spustit apt-get update
&& apt-get install -y libzip-dev wget --no-install-recommends
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
Spustit docker-php-ext-install zip;
CMD bash -c "cd /app && composer install && php -a"
Zdrojový kód je k dispozici přímo: /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile
Výše uvedený soubor používá nástroj Docker Compose k sestavení kontejneru z obrazu PHP 8.1 s nainstalovaným nástrojem Composer a rozšířením AMQP. Navíc spustí intepreter PHP v režimu doplňování, aby kontejner běžel na pozadí.
Strom adresářů a souborů by nyní měl vypadat následovně:
.
├── app1
│ └── Dockerfile
| (...) # Struktura aplikace Symfony
├── app2
│ └── Dockerfile
| (...) # Struktura aplikace Symfony
└── docker-compose.yml
Začněme s app1 a první aplikaci.
V našem příkladu se jedná o aplikaci, která naslouchá a přijímá zprávy z fronty odeslané pomocí nástroje app2 jak je popsáno v požadavcích:
přiřazení práce pracovníkovi v
app2odešle klientovi oznámení
Začněme přidáním požadovaných knihoven. AMQP je nativně podporováno pro symfony/messenger rozšíření. Navíc nainstalujeme monolog/monolog sledovat systémové protokoly pro snadnější analýzu chování aplikací.
cd app1/
symfony composer req amqp ampq-messenger monolog
Po instalaci byl přidán další soubor pod položkou config/packages/messenger.yaml. Jedná se o konfigurační soubor pro komponentu Symfony Messenger a my nepotřebujeme jeho úplná konfigurace.
Nahraďte jej níže uvedeným souborem YAML:
rámec:
messenger:
# Odkomentujte tuto položku (a níže uvedený neúspěšný transport), abyste neúspěšné zprávy odesílali na tento transport pro pozdější zpracování.
# failure_transport: failed
transporty:
# https://symfony.com/doc/current/messenger.html#transport-configuration
external_messages:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
auto_setup: false
exchange:
name: messages
type: direct
default_publish_routing_key: from_external
fronty:
Zprávy: externí: zprávy:
binding_keys: [from_external]
Zdrojový kód je k dispozici přímo: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml
Symfony Messenger se používá pro synchronní a asynchronní komunikaci v aplikacích Symfony. Podporuje řadu transportynebo zdroje pravdy dopravní vrstvy. V našem příkladu používáme rozšíření AMQP, které podporuje systém front událostí RabbitMQ.
Výše uvedená konfigurace definuje nový transport s názvem external_messages, který odkazuje na MESSENGER_TRANSPORT_DSN a definuje přímé naslouchání na zprávy kanál ve sběrnici zpráv. V tomto okamžiku také upravte app1/.env a přidejte příslušnou transportní adresu.
"`env
(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Po přípravě aplikačního rámce a konfiguraci knihoven je čas implementovat obchodní logiku. Víme, že naše aplikace musí reagovat na přiřazení úlohy pracovníkovi. Víme také, že přiřazení úlohy v systémuapp2system změní stav úlohy. Vytvoříme tedy model, který napodobuje změnu stavu, a uložíme jej do cestyapp1/Message/StatusUpdate.php`:

{
public function __construct(protected string $status){}
public function getStatus(): string
{
return $this->status;
}
}
Zdrojový kód je k dispozici přímo: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php
Ještě potřebujeme třídu, která bude implementovat obchodní logiku, když naše mikroslužba obdrží výše uvedenou událost z fronty. Vytvořme tedy třídu Obsluha zpráv v app1/Handler/StatusUpdateHandler.php cesta:

použít PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;
[AsMessageHandler]
class StatusUpdateHandler
{
public function __construct(
protected LoggerInterface $logger,
) {}
public function __invoke(StatusUpdate $statusUpdate): void
{
$statusDescription = $statusUpdate->getStatus();
$this->logger->warning('APP1: {STATUS_UPDATE} - '.$statusDescription);
// zbytek obchodní logiky, tj. odeslání e-mailu uživateli
// $this->emailService->email()
}
}
Zdrojový kód je k dispozici přímo: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php
PHP atributy značně usnadňují práci a znamenají, že se v tomto konkrétním případě nemusíme starat o automatické zapojení nebo servisní prohlášení. Naše mikroslužba pro zpracování událostí domény je připravena, je čas pustit se do druhé aplikace.
Podíváme se na app2 a druhý adresář Aplikace Symfony. Naší myšlenkou je poslat zprávu do fronty, když je pracovníkovi v systému přidělen úkol. Provedeme tedy rychlou konfiguraci AMQP a přimějeme naši druhou mikroslužbu, aby začala publikovat. StatusUpdate události do sběrnice zpráv.
Instalace knihoven je úplně stejná jako u první aplikace.
cd ..
cd app2/
symfony composer req amqp ampq-messenger monolog
Ujistěme se, že app2/.env obsahuje platnou položku DSN pro RabbitMQ:
(...)
MESSENGER_TRANSPORT_DSN=amqp://user:password@rabbitmq:5672//messages
(...)
Zbývá jen nakonfigurovat aplikaci Symfony Messenger v adresáři app2/config/packages/messenger.yaml file:
rámec:
messenger:
# Odkomentujte tuto položku (a níže uvedený neúspěšný transport), abyste neúspěšné zprávy odesílali na tento transport pro pozdější zpracování.
# failure_transport: failed
transporty:
# https://symfony.com/doc/current/messenger.html#transport-configuration
asynchronní:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
# Směrování zpráv na transporty
'AppMessageStatusUpdate': async
Jak vidíte, tentokrát definice transportu směřuje přímo k asynchronní a definuje směrování v podobě odeslání našeho StatusUpdate zprávu do nakonfigurované sítě DSN. To je jediná oblast konfigurace, zbývá jen vytvořit logickou a implementační vrstvu fronty AMQP. Za tímto účelem vytvoříme dvojče StatusUpdateHandler a StatusUpdate třídy v app2.

použít PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;
[AsMessageHandler]
class StatusUpdateHandler
{
public function __construct(
private readonly LoggerInterface $logger,
) {}
public function __invoke(StatusUpdate $statusUpdate): void
{
$statusDescription = $statusUpdate->getStatus();
$this->logger->warning('APP2: {STATUS_UPDATE} - '.$statusDescription);
## obchodní logika, tj. odeslání interního oznámení nebo zařazení do fronty některých jiných systémů
}
}

{
public function __construct(protected string $status){}
public function getStatus(): string
{
return $this->status;
}
}
Zdrojový kód je k dispozici přímo: /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php
Nakonec zbývá jen vytvořit způsob, jak odeslat zprávu do sběrnice zpráv. Vytvoříme jednoduchý Příkaz Symfony k tomu:

použít SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentMessengerMessageBusInterface;
[AsCommand(
name: "app:send"
)]
class SendStatusCommand extends Command
{
public function construct(private readonly MessageBusInterface $messageBus, string $name = null)
{
parent::construct($name);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$status = "Worker X assigned to Y";
$this->messageBus->dispatch(
zpráva: new StatusUpdate($status)
);
return Command::SUCCESS;
}
}
Díky Vstřikování závislostí můžeme použít instanci MessageBusInterface v našem příkazu a odeslat StatusUpdate zprávu prostřednictvím dispatch() do naší fronty. Kromě toho zde používáme také atributy PHP.
To je vše - zbývá jen spustit prostředí Docker Compose a zjistit, jak se naše aplikace chovají.
Pomocí nástroje Docker Compose budou kontejnery s našimi dvěma aplikacemi sestaveny a spuštěny jako samostatné instance, jedinou vrstvou middlewaru bude nástroj rabbitmq kontejneru a naší implementace sběrnice Message Bus.
Z kořenového adresáře projektu spusťme následující příkazy:
cd ../ # ujistěte se, že jste v hlavním adresáři
docker-compose up --build -d
Tento příkaz může chvíli trvat, protože vytváří dva samostatné kontejnery s PHP 8.1 + AMQP a stahuje obraz RabbitMQ. Buďte trpěliví. Po sestavení obrazů můžete spustit náš příkaz z adresy app2 a odeslat některé zprávy do fronty.
docker exec -it app2 php bin/console app:send
Můžete to udělat tolikrát, kolikrát jen můžete. Dokud není spotřebitel vaše zprávy nebudou zpracovány. Jakmile spustíte app1 a spotřebovat všechny zprávy, které se zobrazí na obrazovce.
docker exec -it app1 php bin/console messenger:consume -vv externí_zprávy

Kompletní zdrojový kód spolu s README naleznete v našem veřejném úložišti The Codest Github
Symfony se svými knihovnami a nástroji umožňuje rychlý a efektivní přístup k vývoji moderních technologií. webové aplikace. Pomocí několika příkazů a několika řádků kódu jsme schopni vytvořit moderní komunikační systém mezi aplikacemi. Symfony, stejně jako PHP, je ideální pro vývoj webových aplikací a díky svému ekosystému a snadné implementaci tento ekosystém dosahuje jedněch z nejlepších ukazatelů doby uvedení na trh.
Rychlost však nemusí vždy znamenat kvalitu - ve výše uvedeném příkladu jsme uvedli nejjednodušší a nejrychlejší způsob komunikace. Zvídavější si jistě všimnou, že chybí odpojování doménových událostí mimo aplikační vrstvu - v současné verzi se duplikují a chybí plná podpora pro tzv. Obálka, mimo jiné není Známky. Pro tyto a další zájemce vás zvu k přečtení druhého dílu, kde se budeme věnovat tématu sjednocení doménové struktury aplikací Symfony v prostředí mikroslužeb a probereme druhou populární metodu komunikace mikroslužeb - tentokrát synchronní, založenou na rozhraní REST API.
