StackPHP解释了

tech2022-09-01  115

Today we are going to look at StackPHP and try to understand what this thing is all about. Although this post will have some code, this article will be rather theoretical as we are interested in learning what StackPHP actually is, where it comes from and why it is useful.

今天,我们将看一下StackPHP并尝试了解这是什么一回事。 尽管这篇文章将包含一些代码,但由于我们对学习StackPHP的真正含义,它的来历和用途很有兴趣,因此本文将是理论性的。

As the front page of the StackPHP project says, Stack is a convention for composing HttpKernelInterface middlewares. But, in order to actually understand this definition, we will have to cover a few concepts first. At the end, we will also illustrate the concepts we learned in the context of StackPHP with some example code. This usually makes things much easier to understand.

就像StackPHP项目的首页所说,Stack是构成HttpKernelInterface中间件的约定 。 但是,为了真正理解该定义,我们必须首先涵盖一些概念。 最后,我们还将通过一些示例代码来说明我们在StackPHP上下文中学到的概念。 这通常使事情更容易理解。

什么是HttpKernelInterface? (What is the HttpKernelInterface?)

The HttpKernelInterface can be defined as more than one thing. At its most basic level, it is a PHP interface found inside the Symfony HttpKernel component. But it is more than that. It is a modern PHP pattern that allows us to treat HTTP requests in an object oriented way instead of dealing with superglobals and output functions like echo or header.

可以将HttpKernelInterface定义为一件事。 从最基本的角度来看,它是Symfony HttpKernel组件内部的一个PHP接口。 不仅如此。 这是一种现代PHP模式,允许我们以面向对象的方式处理HTTP请求,而不是处理超全局变量和输出函数(例如echo或header 。

But what does this actually mean?

但是,这实际上意味着什么?

The interface provides a single method called handle() that accepts a $request and is expected to return a $response. The latter are basically wrapper objects around the HTTP specification. For example, in Symfony, it is the responsibility of the HttpFoundation component to create and manage these. So as you can imagine, the $request object contains data about the current user request, while the $response object is responsible for outputting the result of processing the request. But this is already a digression.

该接口提供了一个称为handle()方法,该方法接受$request并期望返回$response 。 后者基本上是围绕HTTP规范的包装对象。 例如,在Symfony中, HttpFoundation组件负责创建和管理它们。 可以想象, $request对象包含有关当前用户请求的数据,而$response对象负责输出处理请求的结果。 但这已经是题外话了。

The interface doesn’t really care about what happens inside the handle() method. This is the responsibility of the class that implements it. For example, the Symfony kernel uses the Event Dispatcher component for managing this. It dispatches a number of events, and listeners to these events handle most of the heavy lifting. This keeps things abstract and decoupled.

该接口实际上并不关心handle()方法内部发生了什么。 这是实现它的类的责任。 例如,Symfony内核使用Event Dispatcher组件进行管理。 它调度许多事件,这些事件的侦听器处理大部分繁重的工作。 这使事物变得抽象和分离。

But to get back to the point, you can regard the HttpKernelInterface as a very simple OO pattern that helps organise the handling of an incoming request for the purpose of turning it into a response.

但是,回到主题,您可以将HttpKernelInterface视为非常简单的OO模式,该模式有助于组织对传入请求的处理,以将其转换为响应。

装饰器模式是什么? (What is the decorator pattern?)

Like many other programming patterns, the decorator pattern is an object oriented way of solving a particular problem. In this case, the problem relates to extending functionality within a class without actually modifying or actually extending the class. The solution is to rather decorate it with the additional needed functionality.

像许多其他编程模式一样,装饰器模式是一种解决特定问题的面向对象的方式。 在这种情况下,问题与在类中扩展功能而不实际修改或扩展类有关。 解决方案是用其他所需的功能来装饰它。

Let’s quickly see a code example as it is the easiest way to understand what this pattern is all about.

让我们快速查看一个代码示例,因为它是了解此模式的最简单方法。

Imagine you have this Action interface and class:

假设您有以下Action接口和类:

interface ActionInterface { public function trigger(); } class Action implements ActionInterface { private function performAction() { return 'Action performed'; } public function trigger() { return $this->performAction(); } }

And you want to be able to provide multiple different versions of this class that contain additional functionality inside the trigger() method. You could extend the class, and this is a valid approach in some cases. However, this can also create different problems down the line if you end up needing something like multiple inheritance (inheriting from multiple classes). PHP 5.4 introduces Traits to help out with these.

并且您希望能够提供此类的多个不同版本,这些版本包含在trigger()方法内部的其他功能。 您可以扩展类,在某些情况下这是一种有效的方法。 但是,如果最终需要诸如多重继承(从多个类继承)之类的东西,这也可能会带来其他问题。 PHP 5.4引入了Traits来帮助解决这些问题。

What you can also do is decorate it with another class that implements the same interface, add your functionality to it and then delegate back to the original one. Here is a very simple example:

您还可以做的是用另一个实现相同接口的类装饰它,向其中添加功能,然后委派回原始接口。 这是一个非常简单的示例:

class NotifiedAction implements ActionInterface { private $action; public function __construct(ActionInterface $action) { $this->action = $action; } public function notifyUser() { // Logic for user notification } public function trigger() { $performed = $this->action->trigger(); $this->notifyUser(); return $performed; } }

As you can see, we now have a NotifiedAction class that implements the same interface and that takes the same interface as a constructor parameter. This acts like a decorator around the parameter object because it wraps around it and adds to its functionality from the outside (in this case sends a notification after the action is performed).

如您所见,我们现在有一个NotifiedAction类,该类实现相同的接口,并且采用与构造函数参数相同的接口。 这就像参数对象周围的装饰器一样,因为它围绕参数对象并从外部添加其功能(在这种情况下,执行操作后会发送通知)。

The reason why the decorator must implement the same interface is to make sure it has the same public API as the decorated one. In other words, the objects need to be more or less interchangeable. This is actually the main drawback of the decorator pattern, as wrapping interfaces with multiple methods can become quite clunky. But let’s get back to our example.

装饰器必须实现相同接口的原因是要确保它具有与装饰器相同的公共API。 换句话说,对象需要或多或少可互换。 这实际上是装饰器模式的主要缺点,因为使用多种方法包装接口可能会变得很笨拙。 但是,让我们回到我们的例子。

Now you have 2 options for triggering actions with the ActionInterface:

现在,您有2个用于使用ActionInterface触发操作的选项:

$action = new Action(); $action->trigger();

And

$action = new NotifiedAction(new Action()); $action->trigger();

And you can continue creating decorators and wrap them into one another like Russian dolls:

您可以继续创建装饰器,并将其像俄罗斯玩偶一样包装在一起:

$action = new EmailNotifiedAction(new NotifiedAction(new Action())); $action->trigger();

This is a very simple example of the decorator pattern. You can have slightly more complex structures in which you do some further abstractions to reduce boilerplate code. But this will be enough for our purposes.

这是装饰器模式的非常简单的示例。 您可以使用稍微复杂一些的结构,在其中进行一些进一步的抽象处理以减少样板代码。 但这足以满足我们的目的。

什么是StackPHP中间件? (What is a StackPHP middleware?)

Now that we have a basic understanding of what the HttpKernelInterface and the decorator pattern are, it’s time to see what StackPHP middlewares are.

既然我们对HttpKernelInterface和装饰器模式有基本的了解,现在该看看什么是StackPHP中间件了。

As I mentioned in the begining, StackPHP is

正如我在一开始提到的,StackPHP是

a convention for composing HttpKernelInterface middlewares.

组成HttpKernelInterface中间件的约定。

In other words, StackPHP is a convention for building middlewares that respect a small number of rules, one of which being their implementation of the HttpKernelInterface. But what is a middleware in this context?

换句话说,StackPHP是用于构建遵循少量规则的中间件的约定,其中之一就是它们对HttpKernelInterface的实现。 但是在这种情况下什么是中间件?

A middleware can be understood as a piece of functionality that gets added to the pipeline that runs between the user and the server (between a request and a response). Rack middlewares are a close example to the StackPHP definition of middlewares. And since it provides a sane pattern for implementing this pipeline, the HttpKernelInterface is a great choice for middlewares to wrap around of.

中间件可以理解为一种功能,已添加到在用户和服务器之间(请求和响应之间)运行的管道中。 机架中间件是StackPHP中间件定义的一个近似示例。 而且,由于HttpKernelInterface为实施此管道提供了一种明智的模式,因此它是中间件要包装的理想选择。

More concretely though, a Stack middleware is a simple PHP object that follows three simple rules:

不过,更具体而言,Stack中间件是一个遵循以下三个简单规则的简单PHP对象:

Implements HttpKernelInterface

实现HttpKernelInterface Decorates another object that implements this interface

装饰实现此接口的另一个对象

Adds functionality to the handle() method and delegates to the original object

向handle()方法添加功能并委托给原始对象

Therefore, an important thing to remember is that StackPHP is not a framework or a library. It doesn’t even have any code per se (apart from a few optional tools to help you implement the conventions).

因此,要记住的重要一件事是StackPHP不是框架或库。 它甚至没有本身的任何代码(除了少数可选的 工具来帮助你实现约定)。

But rather, the goal of the StackPHP project is to promote a framework agnostic way for building code at the HTTP level. It argues that as opposed to framework specific or integrated code, HTTP level code can be stacked into existing applications and this also makes it more shareable and universally compatible. Currently, there are a number of PHP frameworks that use the Symfony HttpKernel component and with which Stack already works. Symfony, Silex, Laravel 5 and Drupal 8 are just a few examples and the hope is that this number will increase in the future.

但是,StackPHP项目的目标是促进一种与框架无关的方式来在HTTP级别构建代码。 它认为与框架特定的代码或集成的代码相反,HTTP级别的代码可以堆叠到现有应用程序中,这也使它更具共享性和通用性。 当前,有许多PHP框架使用Symfony HttpKernel组件,并且Stack已经可以使用该框架 。 Symfony,Silex,Laravel 5和Drupal 8只是一些示例,希望这个数字将来会增加。

堆栈中间件是什么样的? (What does a Stack middleware look like?)

If we apply what we learned in the first two sections, we should now fully understand how to build a Stack middleware. We need to write a class that decorates an HttpKernelInterface object and add our own functionality before or after delegating to the decorated object. So let’s create a dead simple Stack middleware that wraps a Symfony application and performs a custom action before actually returning the response to the user.

如果我们应用在前两节中学到的知识,那么我们现在应该完全了解如何构建Stack中间件。 我们需要编写一个装饰HttpKernelInterface对象的类,并在委派给装饰对象之前或之后添加我们自己的功能。 因此,让我们创建一个简单的,简单的Stack中间件,该中间件包装Symfony应用程序并执行自定义操作,然后再将响应实际返回给用户。

At a basic level, this is the front controller of a Symfony app:

从根本上讲,这是Symfony应用程序的前端控制器:

$kernel = new AppKernel('prod', false); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);

AppKernel implements the HTTPKernelInterface and therefore has a handle() method to which we pass a Request object and from which we expect a Response object. Without even caring about what this method does internally, we can decorate it with our own middleware and add new functionality:

AppKernel实现了HTTPKernelInterface,因此具有一个handle()方法,我们向其传递一个Request对象,并从中获得一个Response对象。 甚至无需关心此方法在内部执行的操作,就可以用我们自己的中间件装饰它并添加新功能:

class CustomAppKernel implements HttpKernelInterface { /** * @var \Symfony\Component\HttpKernel\HttpKernelInterface */ private $kernel; public function __construct(HttpKernelInterface $kernel) { $this->kernel = $kernel; } /** * {@inheritdoc} */ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = TRUE) { // Perform whatever task we want before handling the request // Delegate to the decorated kernel to handle the request as it normally would $response = $this->kernel->handle($request, $type, $catch); // Perform some more tasks after the response has been created // Return the Response return $response; } }

In CustomAppKernel you can see the decorator pattern at work. We are wrapping a HttpKernelInterface object, perform some logic and then delegate to the decorated object. Our Symfony app front controller can look like this now:

在CustomAppKernel您可以看到装饰器模式在起作用。 我们包装了HttpKernelInterface对象,执行一些逻辑,然后委托给装饰的对象。 我们的Symfony应用程序前端控制器现在看起来像这样:

$kernel = new CustomAppKernel(new AppKernel('prod', false)); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();

And that’s it. We have created a Stack middleware. If you want to see some more examples, feel free to check out the middlewares page on the StackPHP website.

就是这样。 我们已经创建了一个Stack中间件。 如果您想查看更多示例,请随时查看StackPHP网站上的中间件页面 。

One thing you’ll notice is the missing call to the terminate() method. If we want to to do that as well, our middleware needs to also implement the TerminableInterface. Alternatively, we can use the StackBuilder to help us stack or middlwares together and that also provides support for kernels that implement this interface.

您会注意到的一件事是缺少对terminate()方法的调用。 如果我们也想这样做,那么我们的中间件还需要实现TerminableInterface 。 另外,我们可以使用StackBuilder帮助我们将堆栈或中间件一起堆叠,并且还为实现此接口的内核提供支持。

StackBuilder (StackBuilder)

The StackBuilder is a small library that helps you build a tree of middlewares. It basically takes away some of the pain of having to manually instantiate and decorate your middlewares by providing a simple API wizard instead. So how does it work?

StackBuilder是一个小型库,可帮助您构建中间件树。 基本上,它通过提供一个简单的API 向导来消除了手动实例化和装饰中间件的痛苦。 那么它是怎样工作的?

Let’s turn back to our example above:

让我们回到上面的示例:

$kernel = new CustomAppKernel(new AppKernel('prod', false)); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send();

With StackBuilder, we can do something like this:

使用StackBuilder,我们可以执行以下操作:

$kernel = new AppKernel('prod', false); $stack = (new Stack\Builder()) ->push('CustomAppKernel'); $kernel = $stack->resolve($kernel);

Using the push() method on the StackBuilder object we can add middlewares onto the stack. In this example, we are wrapping our AppKernel with the CustomAppKernel middleware. This really becomes valuable when you have multiple middlewares you want to stack together. All you have to do is keep chaining on the push() method:

使用StackBuilder对象上的push()方法,我们可以将中间件添加到堆栈中。 在此示例中,我们使用CustomAppKernel中间件包装了AppKernel 。 当您具有要堆叠在一起的多个中间件时,这真的很有价值。 您要做的就是继续在push()方法上链接:

$stack = (new Stack\Builder()) ->push('CustomAppKernel') ->push('AnotherAppKernel') ->push('YetAotherAppKernel);

All of these will wrap one by one the original HttpKernelInterface object. And the resolve() method processes the actual stacking. So now when you call the handle() method on stacked kernel, you are basically calling the handle() method of the CustomAppKernel which wraps AnotherAppKernel which wraps YetAnotherAppKernel which wraps the original AppKernel.

所有这些将一一包装原始HttpKernelInterface对象。 然后resolve()方法处理实际的堆栈。 因此,现在当您在堆栈式内核上调用handle()方法时,您基本上是在调用CustomAppKernel的handle()方法,该方法包装了AnotherAppKernel ,包装了YetAnotherAppKernel ,包装了YetAnotherAppKernel ,包装了原始AppKernel 。

Additionally, the stacked kernel that is returned by resolve() also implements the TerminableInterface and therefore has the terminate() method available. So if we call it, it will delegate to the terminate() method of each middleware in the stack that implements this interface.

此外, resolve()返回的堆栈内核也实现了TerminableInterface ,因此具有terminate()方法可用。 因此,如果调用它,它将委派给实现该接口的堆栈中每个中间件的terminate()方法。

结论 (Conclusion)

In this article we looked at StackPHP and tried to understand what it’s all about. We first talked about the HttpKernelInterface as the core of what Stack conventions try to achieve. We also explained the decorator pattern to better understand how these conventions can be followed in practice. Then, we created a small middleware to see all this in action. Finally, we glanced at the StackBuilder, the utility Stack creators provided that makes the process of stacking middlewares a breeze.

在本文中,我们研究了StackPHP,并试图了解其全部内容。 我们首先讨论了HttpKernelInterface,它是Stack约定试图实现的核心。 我们还解释了装饰器模式,以更好地理解如何在实践中遵循这些约定。 然后,我们创建了一个小型中间件以查看所有这些操作。 最后,我们看了一下StackBuilder,这是Stack Creators提供的实用程序,它使堆叠中间件的过程变得轻而易举。

Have you built your own StackPHP middlewares? Let us know in the comments.

您是否构建了自己的StackPHP中间件? 让我们在评论中知道。

翻译自: https://www.sitepoint.com/stackphp-explained/

相关资源:jdk-8u281-windows-x64.exe
最新回复(0)