专门做淘宝特价的网站,普通网站 seo 多少钱,网站的建设可以起到什么作用是什么原因,什么网站做兼职最好原标题#xff1a;如何用预处理让 PHP 更先进先来点趣事。不久以前#xff0c; 来添加 Python 的 range 语法。然后#xff0c; 大虾 #xff0c;并且 建议为 PHP 添加 C# 风格的 getter 和 setter。我意识到对于一个局外人来说#xff0c;建议和实现新的语言特性是件缓慢…原标题如何用预处理让 PHP 更先进先来点趣事。不久以前 来添加 Python 的 range 语法。然后 大虾 并且 建议为 PHP 添加 C# 风格的 getter 和 setter。我意识到对于一个局外人来说建议和实现新的语言特性是件缓慢的事情所以我打开了自己的编辑器……这篇教程的代码可以在 上找到。它在 PHP^7.1 版本测试生成的代码可以运行在 PHP^5.6|^7.0。宏是如何运行的从我上次谈及宏已经有一段时间了(也许你从来没有听说过他们)。为了更新存储空间他们会采用类似这样的代码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);)}…并将自定义的 PHP 语法如下所示$few many[ 1.. 3];…转化为合法的 PHP 语法如下所示$few eval( $list . $many. ;. $lower . explode( .., 1..3)[0] . ;. $upper . explode( .., 1..3)[1] . ;. return array_slice($list, $lower, $upper - $lower););如果你想了解这是如何运行的可以查看我之前发布的 。秘诀是理解解析器的如何分割代码字符串构建一个宏模式然后将该模式递归地应用于新的语法之上的。但是 没有很好的文档。我们很难知道模式究竟是什么样子的或者最终生成什么样的有效语法。每个新的应用程序都要求编写一个类似这样的教程其他人才能真正理解发生了什么。创建基准代码所以让我们来看看手边的应用程序。我们模仿 C# 的语法向 PHP 添加 getter 和 setter 语法。在我们可以做到这一点之前我们需要有一个好的基准代码用于后续开发。 也许是某种形式的trait我们可以将其添加到需要这个新功能的类中。我们需要实现代码来检查类定义并为每个特殊属性或注释动态创建 getter 和 setter 方法。也许我们可以从定义一个特殊方法名称的格式开始并且使用 __get 和 __set 方法namespaceApp; traitAccessorTrait{ /** * inheritdoc* * paramstring $property * parammixed $value */publicfunction__get($property){ if(method_exists( $this, __get_{$property})) { return$this-{ __get_{$property}}(); } } /** * inheritdoc* * paramstring $property * parammixed $value */publicfunction__set($property, $value){ if(method_exists( $this, __set_{$property})) { return$this-{ __set_{$property}}($value); } }}每个以 __get_ 和 __set_ 命名开始的方法都需要与一个尚未定义的属性相关联。我们可以参考类似下面的语法namespace App; classSprocket{ private$ type{ get { return$ this- type; } set { $ this- type strtoupper($value); } };}…被转化为和下面非常类似的格式namespaceApp; classSprocket{ useAccessorTrait; private$type; privatefunction__get_type(){ return$this-type; } privatefunction__set_type($value){ $this-type strtoupper($value); }}定义所需的宏是这些工作中最难的部分。鉴于文档缺乏(和未广泛使用)并且只有少数有用的异常消息这里面大多是反复验证和试错的结果。我花了几个小时整理出以下几种模式macro ·unsafe { ·ns()· class{ ···body }} {· class{ useAccessorTrait; ···body }}macro ·unsafe { privateT_VARIABLE· var{ get { ···getter } set { ···setter } };} { privateT_VARIABLE· var; privatefunction··concat(__get_ ··unvar(T_VARIABLE·var))(){ ···getter } privatefunction··concat(__set_ ··unvar(T_VARIABLE·var))($value){ ···setter }}好吧让我们看看这两个宏是做什么的我们从匹配 class MyClass {...} 开始并插入我们之前构建的 AccessorTrait。 这里提供了 _get 和 _set 的实现其中将 _get_bar 链接到 print $class-bar 中。我们匹配 accessor 块的语法并将其替换为通用的属性定义后面是几个独立的方法定义。 我们可以在这些函数中封装 get{...} 和 set{...} 块的实现部分。起初当你运行这个代码时你会遇到一个错误。这是因为 ··unvar 函数不是宏处理器的标准组件。这是我不得不添加的部分从 $type 到 type 的转换namespaceYayDSLExpanders; useYayToken; useYayTokenStream; functionunvar(TokenStream $ts): TokenStream{ $str str_replace( $, , (string) $ts); returnTokenStream::fromSequence( newToken( T_CONSTANT_ENCAPSED_STRING, $str ) ) ;}我本可以拷贝(几乎全部)的 stringify 扩展器的代码它是包含在宏解析器代码之中。为了弄清楚 Yay 如何实现的你不需要了解很多关于 Yay 内部结构。将 TokenStream 转换为 string(在此上下文中)意味着你正在获取当前token所标记的字符串的值 - 在本例中为 ··unvar(T_VARIABLE·var) - 并对其执行字符串操作。(string) $ts 变成“$type”而不是“T_VARIABLE·var”。通常当这些宏被放置在要处理的脚本中会自动完成这些。换句话说我们可以创建一个类似于下面的脚本?phpmacro ·unsafe { ...} { ...}macro ·unsafe { ...} { ...}namespace App; traitAccessorTrait{ ...} classSprocket{ private$ type{ get { return$ this- type; } set { $ this- type strtoupper($value); } };}…然后我们可以用下面命令运行它vendor/bin/yay src/Sprocket.pre src/Sprocket.php最后我们就可以使用这些代码了(需要 Composer PSR-4 autoloading)require__DIR__. /vendor/autoload.php;$sprocket newAppSprocket();$sprocket-type acme sprocket; print$sprocket-type; // Acme Sprocket自动转换手动过程就是这样子。在每次更改 src/Sprocket.pre 时谁会想去运行这个 bash 命令呢 幸运的是我们可以将其自动化第一步是定义自定义的自动加载器spl_autoload_register( function($class){ $definitions require__DIR__. /vendor/composer/autoload_psr4.php; foreach($definitions as$prefix $paths) { $prefixLength strlen($prefix); if(strncmp($prefix, $class, $prefixLength) ! 0) { continue; } $relativeClass substr($class, $prefixLength); foreach($paths as$path) { $php $path . /. str_replace( , /, $relativeClass) . .php; $pre $path . /. str_replace( , /, $relativeClass) . .pre; $relative ltrim(str_replace( __DIR__, , $pre), DIRECTORY_SEPARATOR); $macros __DIR__. /macros.pre; if(file_exists($pre)) { // ... convert and load file} } }}, false, true);如 中所述你可以将此文件保存为 autoload.php并使用 files 自动加载功能通过 Composer 的自动加载器包含它。该定义的第一部分直接来自于 的示例实现。我们获得 Composer 的 PSR-4 定义文件对于每个前缀我们检查它是否与当前正在加载的类匹配。如果匹配我们检查每个可能的路径直到我们找到一个 file.pre其中定义了我们的自定义语法。 之后我们获得 macros.pre 文件的内容(在项目基目录中)并创建一个临时文件 - 使用 macros.pre 内容匹配的文件的内容命名。这意味着宏在传递给 Yay 的文件中可用。 待 Yay 编译完 file.pre.interim→file.php 之后我们就删除 file.pre.interim。这个处理过程的代码如下if(file_exists($php)) { unlink($php);}file_put_contents( {$pre}.interim, str_replace( ?php , file_get_contents($macros), file_get_contents($pre) )); exec( vendor/bin/yay {$pre}.interim {$php});$comment # This file is generated, changes you make will be lost. # Make your changes in {$relative} instead.;file_put_contents( $php, str_replace( ?php , ?phpn{$comment}, file_get_contents($php) )); unlink( {$pre}.interim);require_once $php;注意在调用 spl_autoload_register 结束时的那两个布尔值。第一个是标示这个自动加载器是否应该抛出异常加载错误。 第二个是标示这个自动加载器是否应该预先加载到堆栈中。 这把它放在 Composer 自动加载器之前这意味着我们可以在 Composer 尝试加载 file.php 之前转换 file.pre创建一个插件框架这种自动化实现很棒但如果在每个项目中都重新操作是非常浪费的。 如果我们可以仅添加一个 composer require 依赖(为获得一个新的语言功能)就可以正常工作这怎么样呢让我们试试看......首先我们需要创建一个新的 repo包含以下文件composer.json→ 自动加载下列文件functions.php→ 创建宏路径函数(在其他库中可以动态添加自己的宏文件)expanders.php→ 创建扩展器函数比如 ··unvarautoload.php→ augment Composer 的自动加载器将每个其他库的宏文件加载到每个编译的 .prefile 中{name:pre/plugin,require: {php:^7.0,yay/yay:dev-master},autoload: {files: [functions.php,expanders.php,autoload.php] },minimum-stability:dev,prefer-stable:true}上面代码来自 composer.json上面代码来自 functions.php你可能正在想着使用 $GLOBALS 作为存储宏文件路径。这并不重要因为我们可以使用诸多其他方式来存储这些路径。 这里仅仅是演示模式实现的最简单的方法。这部分来自 expanders.php?phpnamespacePre ;if(file_exists(__DIR__. /../../autoload.php)) { define(BASE_DIR, realpath(__DIR__. /../../../));}spl_autoload_register(function($class){ $definitions requireBASE_DIR . /vendor/composer/autoload_psr4.php; foreach($definitions as$prefix $paths) { // ...check $prefixLengthforeach($paths as$path) { // ...create $php and $pre$relative ltrim(str_replace(BASE_DIR, , $pre), DIRECTORY_SEPARATOR); $macros BASE_DIR . /macros.pre; if(file_exists($pre)) { // ...remove existing PHP fileforeach(getMacroPaths() as$macroPath) { file_put_contents( {$pre}.interim, str_replace( ?php , file_get_contents($macroPath), file_get_contents($pre) ) ); } // ...write and include the PHP file} } }}, false, true);这部分来自 autoload.php现在附加的宏插件可以使用这些函数将自己的代码挂接到系统中了...创建新的语言功能通过构建插件代码我们可以将我们的类访问器重构为独立的、可自动应用的功能。 我们需要创建几个文件来实现这一点composer.json→ 用于查找基本插件库并自动加载以下文件macros.pre→ 当前插件的宏代码functions.php→ 将 accessor 宏挂接到基本插件系统中src/AccessorsTrait.php→ 大致上保持不变{name:pre/class-accessors,require: {php:^7.0,pre/plugin:dev-master},autoload: {files: [functions.php],psr-4: {Pre:src} },minimum-stability:dev,prefer-stable:true}这是来自 composer.jsonnamespacePre;addMacroPath( __DIR__. /macros.pre);这是来自 functions.phpmacro · unsafe{ ·ns()· class{ ···body }} { · class{ use PreAccessorsTrait; ···body }}macro · unsafe{ privateT_VARIABLE·variable { get{ ···getter } set{ ···setter } };} { // ...}macro · unsafe{ privateT_VARIABLE·variable { set{ ···setter } get{ ···getter } };} { // ...}macro · unsafe{ privateT_VARIABLE·variable { set{ ···setter } };} { // ...}macro · unsafe{ privateT_VARIABLE·variable { get{ ···getter } };} { // ...}这是来自 macros.pre这个宏文件比以前的版本更冗长。可能有一个更优雅的方式来处理所有的关于 accessors 重定义的排列但我目前还没有找到。整合在一起现在一切都很好地打包了你可以直接使用语言功能。 看看这个快速演示你可以在 Github 上找到这些插件库结语和所有的东西一样这可能被滥用。 宏也不例外。虽然它在概念上很酷 但这个代码绝对不是产品级代码。本文来自https://www.oschina.net/translate/how-to-make-modern-php-more-modern-with-preprocessing关注微信公众号PHP技术大全PHPer升级为大神并不难返回搜狐查看更多责任编辑