8000 Leverage the new Runtime component by nicolas-grekas · Pull Request #787 · symfony/recipes · GitHub
[go: up one dir, main page]

Skip to content

Leverage the new Runtime component #787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occas 8000 ionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 commit merged into from
Mar 23, 2021
Merged

Leverage the new Runtime component #787

1 commit merged into from
Mar 23, 2021

Conversation

nicolas-grekas
Copy link
Member
Q A
License MIT
Doc issue/PR -

This recipe-update is a sidekick of symfony/symfony#36652
As you can see, much of the logic has been removed from the recipe and moved to vendor/. This means it will be easier to upgrade such apps.

Copy link
@ghost 8000 ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
Member
@yceruto yceruto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice :), thanks !

Copy link
Member
@weaverryan weaverryan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Biggest concern is helping to guide users into understanding how this works. The old procedural way (while not as powerful as this) was super readable and it’s even a great way to show how simple symfony is: “you can even see where we create the request then handle it!”

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request does not pass validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

@nicolas-grekas
Copy link
Member Author

PR updated to account for symfony/symfony#37351 and symfony/symfony#37357

Copy link
Member
@yceruto yceruto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better now!

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

@javiereguiluz
Copy link
Member

I haven't followed the related discussions about Runtime component, but let me add this pseudo-random comment here. Looking at this code:

return function (array $context) {
    $kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);

    return new Application($kernel);
};

I wonder if it would be possible and/or desirable to use a proper object instead of a PHP array:

return function (Runtime $runtime) {
    $kernel = new Kernel($runtime->env(), $runtime->debug());

    return new Application($kernel);
};

Method names would be up to be decided:

$kernel = new Kernel($runtime->env(), $runtime->debug());
$kernel = new Kernel($runtime->environment(), $runtime->debugMode());
$kernel = new Kernel($runtime->env(), $runtime->isDebug());
// ...

@nicolas-grekas
Copy link
Member Author

@javiereguiluz I'm not sure creating a DTO for accessing two scalars is worth it. And I'm not sure what else this DTO could do.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

Copy link
@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request passes validation.

fabpot added a commit to symfony/symfony that referenced this pull request Mar 10, 2021
…m global state (nicolas-grekas)

This PR was merged into the 5.3-dev branch.

Discussion
----------

[Runtime] a new component to decouple applications from global state

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | symfony/symfony-docs#15081

Follow up of #36652, see discussion there.

What if we could decouple the bootstrapping logic of our apps from any global state?

This PR makes it possible via a new proposed `symfony/runtime` component.

The immediate benefit this provides is easier maintenance of Symfony apps: code that is currently shipped by recipes will be able to move to `vendor/`. Read the previous sentence twice, this is big :)
Check the following PR to see how far this goes: symfony/recipes#787

The longer-term benefit is being able to run the exact same app under several runtimes: PHP-FPM, CLI, but also PHP-PM and similar. Thanks to the proposed interface, this benefit could span to any PHP apps; not only to apps using the Symfony HttpKernel/HttpFoundation components. This part could be moved to `symfony/contracts` in the future.

Performance-wise, I measured no significant difference with the current way of running apps.

RuntimeInterface
----------------

The core of this component is the `RuntimeInterface` which describes a high-order
runtime logic.

It is designed to be totally generic and able to run any application outside of
the global state in 6 steps:

 1. the main entry point returns a callable that wraps the application;
 2. this callable is passed to `RuntimeInterface::getResolver()`, which returns a
    `ResolverInterface`; this resolver returns an array with the (potentially
    decorated) callable at index 0, and all its resolved arguments at index 1;
 3. the callable is invoked with its arguments; it returns an object that
    represents the application;
 4. that object is passed to `RuntimeInterface::getRunner()`, which returns a
    `RunnerInterface`: an instance that knows how to "run" the object;
 5. that instance is `run()` and returns the exit status code as `int`;
 6. the PHP engine is exited with this status code.

This process is extremely flexible as it allows implementations of
`RuntimeInterface` to hook into any critical steps.

Autoloading
-----------

This package registers itself as a Composer plugin to generate a
`vendor/autoload_runtime.php` file. This file shall be required instead of the
usual `vendor/autoload.php` in front-controllers that leverage this component
and return a callable.

Before requiring the `vendor/autoload_runtime.php` file, set the
`$_SERVER['APP_RUNTIME']` variable to a class that implements `RuntimeInterface`
and that should be used to run the returned callable.

Alternatively, the class of the runtime can be defined in the `extra.runtime.class`
entry of the `composer.json` file.

A `SymfonyRuntime` is used by default. It knows the conventions to run
Symfony and native PHP applications.

Examples
--------

This `public/index.php` is a "Hello World" that handles a "name" query parameter:
```php
<?php

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $request, array $context): void {
    // $request holds keys "query", "body", "files" and "session",
    // which map to $_GET, $_POST, $_FILES and &$_SESSION respectively

    // $context maps to $_SERVER

    $name = $request['query']['name'] ?? 'World';
    $time = $context['REQUEST_TIME'];

    echo sprintf('Hello %s, the current Unix timestamp is %s.', $name, $time);
};
```

This `bin/console.php` is a single-command "Hello World" application
(run `composer require symfony/console` before launching it):
```php
<?php

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 function (Command $command) {
    $command->addArgument('name', null, 'Who should I greet?', 'World');

    return $command->setCode(function (InputInterface $input, OutputInterface $output) {
        $name = $input->getArgument('name');
        $output->writeln(sprintf('Hello <comment>%s</>', $name));
    });
};
```

The `SymfonyRuntime` can resolve and handle many types related to the
`symfony/http-foundation` and `symfony/console` components.
Check its source code for more information.

Commits
-------

61b32ab [Runtime] a new component to decouple applications from global state
Copy link
Member
@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im happy with this PR.

@chalasr
Copy link
Member
chalasr commented Mar 23, 2021

Although this may seem to add some extra mystification/complexity around the boostraping logic (which is currently super simple for the minimal/basic use case), it's really cool to see how it can reduce the learning curve when it comes to bootstrapping "special" applications like e.g. lambda or roadrunner (thanks @php-runtime), which become more and more common nowadays.

I'm 👍 here.

Copy link
Member
@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you Nicolas and all the reviewers.

@javiereguiluz That is still possible, but we need to make changed in the component if we want to add that DTO. I dont think that is a blocker for merging this.

@ghost ghost merged commit 6fb03bf into symfony:master Mar 23, 2021
nicolas-grekas added a commit to symfony/skeleton that referenced this pull request Mar 23, 2021
This PR was submitted for the 5.x branch but it was merged into the 5.3 branch instead.

Discussion
----------

Add Runtime component

If symfony/recipes#787 is merged and I run

```
symfony new acme --version=next
```

Now I will have a front controller that require `dirname(__DIR__).'/vendor/autoload_runtime.php'`, but that file does not exist.

If you are starting a new Symfony project, you will run it somehow => hence, you need the runtime component.

Commits
-------

54c44b6 Add Runtime component
@nicolas-grekas nicolas-grekas deleted the runtime branch March 23, 2021 16:48
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0