Компонент Runtime
Дата оновлення перекладу 2024-05-03
Компонент Runtime
Компонент Runtime відокремлює логіку самозавантаження від будь-якого глобального стану, щоб переконатися в тому, що додаток може працювати з середовищами на кшталт PHP-PM, ReactPHP, Swoole та ін. без змін.
Установка
1
$ composer require symfony/runtime
Note
Якщо ви встановлюєте цей компонент поза додатком Symfony, вам потрібно підключити
файл vendor/autoload.php
у вашому коді для включення механізму автозавантаження
класів, наданих Composer. Детальніше можна прочитати у цій статті.
Використання
Компонент Runtime вилучає більшість логіки самозавантаження як так названі
середовища виконання, дозволяюючи вам писати фронт-контролери загальним чином.
Наприклад, компонент Рантайм дозволяє public/index.php
Symfony виглядати так:
1 2 3 4 5 6 7 8
// public/index.php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context): Kernel {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};
Отже, як же працює цей фронт-контролер? Спочатку, спеціальний файл
autoload_runtime.php
автоматично створюється плагіном Composer в компоненті.
Цей файл виконує наступну логіку:
- Інстанціює RuntimeInterface;
- Викличне (повернене
public/index.php
) передається Рантайму, робота якого полягає в розпізнаванні аргументів (у цьому прикладі:array $context
); - Потім, це викличне викликається для отримання додатку (
App\Kernel
); - Нарешті, Runtime використовується для запуску додатку (тобто, виклик
$kernel->handle(Request::createFromGlobals())->send()
).
Caution
Якщо ви використовуєте опцію Composer --no-plugins
, файл autoload_runtime.php
не буде створено.
Якщо ви використовуєте опцію Composer --no-scripts
, переконайтеся в тому, що ваша
версія Composer - >=2.1.3
; інакше файл autoload_runtime.php
не буде створений.
Щоб створити консольний додаток, код самозавантаження виглядатиме так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/usr/bin/env php
<?php
// bin/console
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context): Application {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
// повернення "Application" змушує Рантайм запустити Консольний
// додаток замість HTTP Ядра
return new Application($kernel);
};
Вибір середовища виконання
Середовище виконання за замовчуванням - SymfonyRuntime. Воно чудово працює у більшості додатків, що працюють з веб-сервером, який використовує PHP-FPM на кшталт Nginx або Apache.
Компонент також надає GenericRuntime, який
використовує суперглобальні $_SERVER
, $_POST
, $_GET
, $_FILES
і
$_SESSION
. Ви можете також використати користувацьке середовище виконання
(наприклад, щоб інтегруватися зі Swoole або AWS Lambda).
Використайте змінну середовища APP_RUNTIME
або вкажіть extra.runtime.class
в composer.json
, щоб змінити клас Рантайму:
1 2 3 4 5 6 7 8 9 10
{
"require": {
"...": "..."
},
"extra": {
"runtime": {
"class": "Symfony\\Component\\Runtime\\GenericRuntime"
}
}
}
Використання Runtime
Runtime відповідає за передачу аргументів у замикання та запуск додатку, який повертається цим замиканням. SymfonyRuntime і GenericRuntime підтримують певну кількість аргументів та різних додатків, які ви можете використовувати у ваших фронт-контролерах.
Розвʼязувані аргументи
Замикання, повернене з фронт-контролера, може мати 0 або більше аргументів:
1 2 3 4 5 6 7 8 9 10
// public/index.php
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (InputInterface $input, OutputInterface $output): Application {
// ...
};
Наступні аргументи підтримуються SymfonyRuntime
:
- Request
- Запит, створений з глобальностей.
- InputInterface
- Введення для читання опцій та аргументів.
- OutputInterface
- Виведення консолі для відображення в CLI зі стилем.
- Application
- Додаток для створення CLI-додатків.
- Command
-
Для створення CLI-додатків команди одного рядку (використовуючи
Command::setCode()
).
А ці аргументи підтримуються як SymfonyRuntime
, так і
GenericRuntime
(важливі як тип так і імʼя змінної):
array $context
-
Те ж саме, що і
$_SERVER
+$_ENV
. array $argv
-
Аргументи, передані команді (те ж саме, що і
$_SERVER['argv']
). array $request
-
З ключами
query
,body
,files
иsession
.
Розвʼязувані додатки
Додаток, повернений замиканням нижче, є Ядром Symfony. Однак, підтримується низка різних додатків:
1 2 3 4 5 6 7 8
// public/index.php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return static function (): Kernel {
return new Kernel('prod', false);
};
SymfonyRuntime
може працювати з такими додатками:
- HttpKernelInterface
- Додаток буде запущений з HttpKernelRunner, як і "стандартний" додаток Symfony.
- Response
-
Відповідь буде виведена ResponseRunner:
1 2 3 4 5 6 7 8
// public/index.php use Symfony\Component\HttpFoundation\Response; require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return static function (): Response { return new Response('Hello world'); };
- Command
-
Для написання додатків одного рядку. Це буде використовувати ConsoleApplicationRunner:
1 2 3 4 5 6 7 8 9 10 11 12 13
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return static function (Command $command): Command { $command->setCode(static function (InputInterface $input, OutputInterface $output): void { $output->write('Hello World'); }); return $command; };
- Application
-
Корисно для консольних додатків з більш ніж однією командою. Це буде використовувати ConsoleApplicationRunner:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return static function (array $context): Application { $command = new Command('hello'); $command->setCode(static function (InputInterface $input, OutputInterface $output): void { $output->write('Hello World'); }); $app = new Application(); $app->add($command); $app->setDefaultCommand('hello', true); return $app; };
GenericRuntime
і SymfonyRuntime
також підтримують такі загальні
додатки:
- RunnerInterface
-
RunnerInterface
- це спосіб використовувати користувацький додаток зі спільним Рантаймом:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// public/index.php use Symfony\Component\Runtime\RunnerInterface; require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return static function (): RunnerInterface { return new class implements RunnerInterface { public function run(): int { echo 'Hello World'; return 0; } }; };
callable
-
Ваш "додаток" також може бути
callable
. Перше викилкане поверне "додаток", а друге викличне буде самим "додатком":1 2 3 4 5 6 7 8 9 10 11 12
// public/index.php require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return static function (): callable { $app = static function(): int { echo 'Hello World'; return 0; }; return $app; };
void
-
Якщо викличне нічого не повертає,
SymfonyRuntime
припустить, що все добре:1 2 3 4 5
require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; return function (): void { echo 'Hello world'; };
Використання опцій
Деяка поведінка середовищ виконання може бути змінена за допомогою їх опцій. Вони
можуть бути встановлені, використовуючи змінну середовища APP_RUNTIME_OPTIONS
:
1 2 3 4 5 6 7
$_SERVER['APP_RUNTIME_OPTIONS'] = [
'project_dir' => '/var/task',
];
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
// ...
Ви такоже можете сконфігурувати extra.runtime.options
в composer.json
:
1 2 3 4 5 6 7 8 9 10
{
"require": {
"...": "..."
},
"extra": {
"runtime": {
"project_dir": "/var/task"
}
}
}
Наступні опції підтримуються SymfonyRuntime
:
env
(за замовчуванням: змінна середовищаAPP_ENV
або"dev"
)- Для визначення назви середовища, в якому виконується додаток.
disable_dotenv
(за замовчуванням:false
)-
Для відключення пошуку файлів
.env
. dotenv_path
(за замовчуванням:.env
)- Для визначення шляху файлів dot-env.
dotenv_overload
(за замовчуванням:false
)-
Для вказання Dotenv, чи перевизначати змінні
.env
на.env.local
(або інші файли.env.*
). use_putenv
-
Для вказання Dotenv встановити змінні середовища, використовуючи
putenv()
(НЕ РЕКОМЕНДУЄТЬСЯ). prod_envs
(за замовчуванням:["prod"]
)- Для визначення середовищ виробництва.
test_envs
(за замовчуванням:["test"]
)- Для визначення назв тестових середовищ.
Крім цього, GenericRuntime
і SymfonyRuntime
також підтримують такі опції:
debug
(за замовчуванням: значення змінної середоовища, визначеної опцією-
debug_var_name
(зазвичай -APP_DEBUG
), абоtrue
, якщо така змінна серредовища не визначена) Переключає режим налагодження додатків Symfony (наприклад, щоб відображати помилки) runtimes
-
Маршрутизує "типи додатків" до реалізації
GenericRuntime
, яка знає, як працювати з кожним з них. error_handler
(за замовчуванням: BasicErrorHandler або SymfonyErrorHandler дляSymfonyRuntime
)- Визначає клас, який потрібно використати для обробки PHP-помилок.
env_var_name
(за замовчуванням:"APP_ENV"
)- Визначає імʼя змінної середовища, яка зберігає імʼя середовища конфігурації , щоб викоритати при запуску додатку.
debug_var_name
(за замовчуванням:"APP_DEBUG"
)- Визначає імʼя змінної середовища, яка зберігає значення прапорця режиму налагодження , щоб викоритати при запуску додатку.
Створіть своє власне середовище виконання
Це просунута тема, яка описує внутрішній процес компонента Рантайм.
Використання компонента Runtime надає переваги супроводжуючим, так як логіка самозавантаження може бути версіонована як частина звичайного пакету. Якщо автор додатку вирішить використовувати цей компонент, супроводжуючий пакету класу Рантайм матиме більше контролю та зможе виправляти помилки та додавати функції.
Компонент Runtime створено так, щоб бути максимально загальним та мати можливість запускати будь-який додаток поза глобальним станом за 6 кроків:
- Основна точка входу повертає викличне ("app"), що огортає додаток;
- Викличне додатку передається
RuntimeInterface::getResolver()
, який повертає ResolverInterface. Цей розвʼязувач повертає масив з викликаним додатку (або щось, що оформлює це викликане) з індексом 0, і всі його дозволені аргументи з індексом 1. - Викличне додатку викликається з його аргументами і поверне обʼєкт, який являє собою додаток.
- Цей обʼєкт додатку передається
RuntimeInterface::getRunner()
, який повертає RunnerInterface: екземпляр, який знає, як "запускати" обʼєкт додатку. RunnerInterface::run(object $application)
викликається та повертає статус-код виходу якint
.- PHP-двигун завершує роботу з цим статус-кодом.
При створенні нового середовища виконання, важливо подумати про дві речі: по-перше, які аргументи буде використовувати кінцевий користувач? По-друге, як виглядатиме додаток користувача?
Наприклад, уявіть, що ви хочете створити середовище виконання для ReactPHP:
Які аргументи буде використовувати кінцевий користувач?
Для спільного додатку ReactPHP, зазвичай не вимагається якихось особливих аргументів. Це означає, що ви можете використати GenericRuntime.
Як виглядатиме додаток користувача?
Також не існує типового додатку React, тому ви можете захотіти покластися на інтерфейси PSR-15 для обробки HTTP-запиту.
Однак, додатку ReactPHP буде необхідна деяка логіка для запуску. Ця логіка додається у новий клас, що реалізує RunnerInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use React\EventLoop\Factory as ReactFactory;
use React\Http\Server as ReactHttpServer;
use React\Socket\Server as ReactSocketServer;
use Symfony\Component\Runtime\RunnerInterface;
class ReactPHPRunner implements RunnerInterface
{
public function __construct(
private RequestHandlerInterface $application,
private int $port,
) {
}
public function run(): int
{
$application = $this->application;
$loop = ReactFactory::create();
// сконфігуруйте ReactPHP, щоб коректно обробити додаток PSR-15
$server = new ReactHttpServer(
$loop,
function (ServerRequestInterface $request) use ($application): ResponseInterface {
return $application->handle($request);
}
);
// запустіть сервер ReactPHP
$socket = new ReactSocketServer($this->port, $loop);
$server->listen($socket);
$loop->run();
return 0;
}
}
Розширюючи GenericRuntime
, ви гарантуєте, що додаток завжди буде використовувати
ReactPHPRunner
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
use Symfony\Component\Runtime\GenericRuntime;
use Symfony\Component\Runtime\RunnerInterface;
class ReactPHPRuntime extends GenericRuntime
{
private int $port;
public function __construct(array $options)
{
$this->port = $options['port'] ?? 8080;
parent::__construct($options);
}
public function getRunner(?object $application): RunnerInterface
{
if ($application instanceof RequestHandlerInterface) {
return new ReactPHPRunner($application, $this->port);
}
// якщо це не додаток PSR-15, використайте GenericRuntime, щоб
// запустити додаток (див. "Resolvable Applications" вище)
return parent::getRunner($application);
}
}
Кінцевий користувач тепер зможе створювати фронт-контролер на кшталт:
1 2 3 4 5
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context): SomeCustomPsr15Application {
return new SomeCustomPsr15Application();
};