php 宏任务和微任务

tech2022-09-03  102

php 宏任务和微任务

I was originally going to call this “Micro Macros with Márcio’s Perfectly Pragmatic Pre-Processor library”, but I didn’t think Bruno would approve…

我本来打算将其称为“具有Márcio的Perfectly Pragmatic预处理程序库的微宏”,但我不认为Bruno会赞成…

I get really excited when developers feel empowered to create new tools, and even new languages with which to solve their problems.

当开发人员感到有能力创建新工具甚至解决问题的新语言时,我会感到非常兴奋。

You see, many developers come to PHP from other languages. And many PHP developers can code in more than one language. Often there are things in those languages — small syntax sugars — that we appreciate and even miss when we’re building PHP things.

您会看到,许多开发人员都是从其他语言来使用PHP的。 许多PHP开发人员可以使用多种语言进行编码。 通常,在构建PHP东西时,我们会欣赏甚至错过这些语言中的东西(小的语法糖)。

Adding these to a language, at a compiler level, is hard (or is it?). That is unless you built the compiler and/or know how they work. We’re not going to do anything that technical, but we’re still going to be empowered.

在编译器级别将这些代码添加到一种语言很困难( 或者是吗? )。 除非您构建了编译器和/或不知道它们如何工作。 我们不会做任何技术性的事情,但是我们仍然会获得授权。

When I used to write Ruby (or languages similar in this regard), I used to use list index ranges. They look something like this:

当我过去编写Ruby(或与此类似的语言)时,我曾经使用列表索引范围。 他们看起来像这样:

few = many[1..3]

We can expect code like that to take the second, third and fourth item of the many list, and assign them to the few variable. We can do something similar, using array_slice:

我们可以期望像这样的代码占用many列表的第二,第三和第四项,并将它们分配给few变量。 我们可以使用array_slice做类似的事情:

$few = array_slice($many, 1, 3);

I think the Ruby equivalent is far more elegant. We can also use variables and negative values for the lower and upper bounds of the range. It’s brilliant!

我认为与Ruby相当的东西要优雅得多。 我们还可以将变量和负值用于范围的上下限。 这个棒极了!

宏入门 (Getting Started with Macros)

Inspired by a recent SitePoint post, I decided to try and add this syntax to my applications. The trouble is I don’t understand the PHP interpreter well enough to be able to add it. Then I remembered Márcio Almada’s Yay library. It adds macros through pre-processing. Here’s an example of something simple you can do with it:

受最近SitePoint帖子的启发,我决定尝试将此语法添加到我的应用程序中。 问题是我对PHP解释器的理解不够,无法添加它。 然后我想起了马尔西奥·阿尔马达(MárcioAlmada)的Yay图书馆 。 它通过预处理添加宏。 这是您可以使用的简单示例:

macro { unless (···condition) { ···body } } >> { if (!(···condition)) { ···body } } $condition = false; unless ($condition) { print "look ma! macros..."; }

That example is straight out the readme (with a few style differences).

该示例完全是自述文件(有一些样式差异)。

In order to run this, we need to download the pre-processor:

为了运行此程序,我们需要下载预处理器:

$ composer require yay/yay:dev-master

Once that’s downloaded, and you’ve saved the PHP-like code above to a file (let’s call it unless.yphp), we can compile it to regular PHP:

下载完成后,您已将上述类似PHP的代码保存到文件中(我们将其unless.yphp ),我们可以将其编译为常规PHP:

$ vendor/bin/yay unless.yphp >> unless.php

The result will look something like:

结果将类似于:

$condition = false; if (!($condition)) { print "look ma! macros..."; }

这一切如何运作 (How This All Works)

Yay implements a parser. It breaks a code string up into tokens, constructs an Abstract Syntax Tree and puts the PHP code back together with all the macro stuff replaced with real PHP code.

Yay实现了一个解析器。 它将代码字符串分解为令牌,构造一个抽象语法树,并将PHP代码与所有用实际PHP代码替换的宏内容放回原处。

These concepts can be difficult to get, at first. I suggest you read this series, which explains some of them using tools you know well.

首先,这些概念可能很难理解。 我建议您阅读本系列文章 ,其中使用您熟知的工具来解释其中的一些内容。

When Yay matches the unless pattern we defined, it essentially does a string replace around the condition and body. We can use this to great effect, for the language syntax we want to add…

当Yay匹配我们定义的unless模式时,它实际上是在condition和body周围进行字符串替换。 对于我们要添加的语言语法,我们可以使用它来产生很大的效果……

添加我们的语法 (Adding Our Syntax)

The first thing we need to do is identify the expression which will match a range index:

我们需要做的第一件事是识别与范围索引匹配的表达式:

macro { T_VARIABLE·A[ T_VARIABLE·B..T_VARIABLE·C ] } >> { array_slice( T_VARIABLE·A, T_VARIABLE·B, T_VARIABLE·C - T_VARIABLE·B ) }

This macro expression looks for a variable, like $many and labels it A. It will only match if it sees the equivalent of $many[$lower..$upper], which it will replace with:

该宏表达式查找变量,例如$many并将其标记为A 仅当它看到等效于$many[$lower..$upper] ,它将匹配,并将其替换为:

array_slice( $many, $lower, $upper - $lower );

The array_slice function parameters are source array, starting offset and number of items to get. This is slightly different to the range syntax, because the range syntax defines a starting offset and an ending offset. We translate between the two by subtracting the upper bound from the lower bound.

array_slice函数的参数是源数组,起始偏移量和要获取的项目数。 这与范围语法略有不同,因为范围语法定义了起始偏移量和结束偏移量。 我们通过从下限减去上限来在两者之间进行翻译。

T_VARIABLE is an AST token type, which identifies variables defined in a code string. There are quite a few different token types, but luckily we don’t have to remember them all…

T_VARIABLE是AST令牌类型,用于标识代码字符串中定义的变量。 有很多不同的令牌类型,但是幸运的是我们不必全部记住它们。

We can try this, with some Yay PHP:

我们可以用一些Yay PHP尝试一下:

macro { T_VARIABLE·A[ T_VARIABLE·B..T_VARIABLE·C ] } >> { array_slice( T_VARIABLE·A, T_VARIABLE·B, T_VARIABLE·C - T_VARIABLE·B ) } $many = [ "She walks in beauty", "like the night", "of cloudless climes", "and starry skies", "And all that's best", "of dark and bright", "meet in her aspect", "and her eyes", "...", ]; $lower = 4; $upper = 8; $few = $many[$lower..$upper];

When we run this through the conversion process, we get something like:

在转换过程中进行操作时,会得到类似以下内容的信息:

$many = [ "She walks in beauty", "like the night", "of cloudless climes", "and starry skies", "And all that's best", "of dark and bright", "meet in her aspect", "and her eyes", "...", ]; $lower = 4; $upper = 8; $few = array_slice( $many, $lower, $upper - $lower );

This is a good start. We still want to allow plain integer bounds, which requires slightly more complex macro code:

这是一个好的开始。 我们仍然希望允许纯整数范围,这需要稍微复杂一些的宏代码:

macro { →(···expression) } >> { ··stringify(···expression) } macro { T_VARIABLE·A[ ···range ] } >> { eval( '$list = ' . →(T_VARIABLE·A) . ';' . '$lower = ' . explode('..', →(···range))[0] . ';' . '$upper = ' . explode('..', →(···range))[1] . ';' . 'return array_slice($list, $lower, $upper - $lower);' ) }

Let’s take this one step at a time. We begin by defining a macro to convert pattern matches to strings. ··stringify(...) is an expansion (which means it transforms other matches). It takes a match and converts it directly to a string. We can see this happening in the following example:

让我们一次迈出这一步。 我们首先定义一个宏,以将模式匹配转换为字符串。 ··stringify(...)是一个扩展(表示它可以转换其他匹配项)。 它需要一个匹配项并将其直接转换为字符串。 我们可以在以下示例中看到这种情况:

macro { convert(···expression) } >> { ··stringify(···expression) } convert($a, $b, $c);

If we run this code through Yay, we’ll see the following:

如果通过Yay运行此代码,则会看到以下内容:

'$a, $b, $c';

I’ve chosen to create a kind of shorthand macro, converting →(...) to ··stringify(...), to make further macros more concise.

我选择创建一种速记宏,将→(...)转换为··stringify(...) ,以使其他宏更加简洁。

I ran into a couple of problems trying to capture numbers in the index range syntax. By the time Yay gets hold of the AST, 4..8 is tokenized as 4. and .8; instead of 4, .., and 8. This generates a parser error before Yay can apply the macros. A way around this is to convert the index range to a string and start parsing it from there.

我在尝试使用索引范围语法捕获数字时遇到了两个问题。 在Yay掌握AST时, 4..8标记为4.和.8 ; 而不是4 , ..和8 。 在Yay可以应用宏之前,这将生成解析器错误。 一种解决方法是将索引范围转换为字符串,然后从那里开始对其进行解析。

An elegant way to do this would be to pass the index range string to a function, along with the source array. Unfortunately, PHP scope rules mean variable range bounds won’t be available inside the function, making it a bit useless.

一种完美的方法是将索引范围字符串与源数组一起传递给函数。 不幸的是,PHP作用域规则意味着可变范围边界在函数内部将不可用,这使其变得毫无用处。

The easiest way around this issue is to reference the variables inside a string, and eval them. The way this works is:

解决此问题的最简单方法是引用字符串中的变量,并将其eval 。 它的工作方式是:

$many is matched with T_VARIABLE·A

$many与T_VARIABLE·A匹配

4..8 is matched with ···expression

4..8匹配···expression

Inside eval, $lower is defined as the first array index after exploding the string 4..8 by ..

在eval内部, $lower定义为将字符串4..8为..后的第一个数组索引..

$upper is defined as the second array index of this explosion

$upper定义为该爆炸的第二个数组索引

The return value, of this eval string, is the original array_slice code we used before

此eval字符串的返回值是我们之前使用的原始array_slice代码

Any of the following lines will be matched by this macro:

以下任一行将与此宏匹配:

$lower = 4; $upper = 8; $few = $many[$lower..$upper]; $few = $many[4..8]; $few = $many[4..$upper]; $few = $many[$lower..8];

…and they will generate code resembling the following:

…他们将生成类似于以下内容的代码:

$few = eval( '$list = ' . '$many' . ';'. '$lower = ' . explode('..', '$lower..$upper')[0] . ';' . '$upper = ' . explode('..', '$lower..$upper')[1] . ';' . 'return array_slice($list, $lower, $upper - $lower);' ); $few = eval( '$list = ' . '$many' . ';'. '$lower = ' . explode('..', '4..8')[0] . ';' . '$upper = ' . explode('..', '4..8')[1] . ';' . 'return array_slice($list, $lower, $upper - $lower);' ); $few = eval( '$list = ' . '$many' . ';'. '$lower = ' . explode('..', '4..$upper')[0] . ';' . '$upper = ' . explode('..', '4..$upper')[1] . ';' . 'return array_slice($list, $lower, $upper - $lower);' ); $few = eval( '$list = ' . '$many' . ';'. '$lower = ' . explode('..', '$lower..8')[0] . ';' . '$upper = ' . explode('..', '$lower..8')[1] . ';' . 'return array_slice($list, $lower, $upper - $lower);' );

That’s probably as clean as we can make this, given the limitations of variable scoping and the parser. It’s not the nicest PHP to look at, but it does the job. In the meantime, we can slice an array with $many[4..8]…

鉴于变量作用域和解析器的局限性,这可能和我们所做的一样干净。 它不是最好看PHP,但是可以完成工作。 同时,我们可以使用$many[4..8]来切片一个数组。

If you found this interesting, or have interesting ideas for how this library can be used, consider leaving a comment below.

如果您觉得这个有趣,或者对如何使用该库有有趣的想法,请考虑在下面留下评论。

翻译自: https://www.sitepoint.com/php-macros-for-fun-and-profit/

php 宏任务和微任务

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