海外社媒SNS代运营Tiktok代运营公司
Revive Old Posts

营销型WordPress外贸多语言独立站建设+谷歌SEO优化+谷歌关键字广告投放,就找WP花园!深圳公司,技术实力雄厚,用效果说话!详情咨询info@wordpresshy.com

在理想情况下,我们应该为所有网站使用 PHP 8.0(撰写本文时的最新版本),并在新版本发布后立即更新。 但是,开发人员通常需要使用以前的 PHP 版本,例如在为 WordPress 创建公共插件或使用阻碍升级网络服务器环境的遗留代码时。

在这些情况下,我们可以放弃使用最新的 PHP 代码的希望。 但是还有一个更好的选择:我们仍然可以使用 PHP 8.0 编写我们的源代码并将其转换为以前的 PHP 版本——甚至是 PHP 7.1。

在本指南中,我们将教您有关转译 PHP 代码所需的一切知识。

什么是转译?

转译将源代码从一种编程语言转换为相同或不同编程语言的等效源代码。

转译在 Web 开发中并不是一个新概念:客户端开发人员很可能熟悉 Babel,一种 JavaScript 代码转译器。

Babel 将 JavaScript 代码从现代 ECMAScript 2015+ 版本转换为与旧浏览器兼容的旧版本。 例如,给定一个 ES2015 箭头函数:

[2, 4, 6].map((n) => n * 2);

…Babel 会将其转换为 ES5 版本:

海外社媒SNS代运营Tiktok代运营公司
[2, 4, 6].map(function(n) {
  return n * 2;
});

什么是转译 PHP?

Web 开发中潜在的新事物是转换服务器端代码的可能性,尤其是 PHP。

转译 PHP 的工作方式与转译 JavaScript 的方式相同:现代 PHP 版本的源代码被转换为旧 PHP 版本的等效代码。

按照与之前相同的示例,来自 PHP 7.4 的箭头函数:

$nums = array_map(fn($n) => $n * 2, [2, 4, 6]);

…可以转换成其等效的 PHP 7.3 版本:

$nums = array_map(
  function ($n) {
    return $n * 2;
  },
  [2, 4, 6]
);

箭头函数可以转译,因为它们是语法糖,即产生现有行为的新语法。 这是唾手可得的果实。

但是,也有一些新功能会创建新行为,因此,以前版本的 PHP 将没有等效代码。 PHP 8.0 中引入的联合类型就是这种情况:

function someFunction(float|int $param): string|float|int|null
{
  // ...
}

在这些情况下,只要新功能需要用于开发而不是用于生产,仍然可以进行转译。 然后,我们可以简单地从转译的代码中完全删除该功能,而不会造成严重后果。

一个这样的例子是联合类型。 此功能用于检查输入类型与其提供的值之间是否不匹配,这有助于防止错误。 如果与类型发生冲突,则开发中已经存在错误,我们应该在代码到达生产环境之前捕获并修复它。

因此,我们可以从生产代码中删除该功能:

function someFunction($param)
{
  // ...
}

如果错误仍然在生产中发生,则抛出的错误消息将不如我们有联合类型时精确。 然而,首先能够使用联合类型克服了这种潜在的缺点。

在一个完美的世界中,我们应该能够在我们所有的网站上使用 PHP 8.0 并在新版本发布后立即更新它😌 但情况并非总是如此。 在此处了解有关转译 PHP 代码的所有信息👇点击推文

转译 PHP 代码的优势

转译使人们能够使用最新版本的 PHP 编写应用程序,并生成一个也可以在运行旧版本 PHP 的环境中运行的版本。

这对于为遗留内容管理系统 (CMS) 创建产品的开发人员特别有用。 例如,WordPress 仍然正式支持 PHP 5.6(即使它推荐 PHP 7.4+)。 运行 PHP 5.6 到 7.2 版本的 WordPress 站点的百分比——它们都是生命周期终止 (EOL),这意味着它们不再接收安全更新——高达 34.8%,而那些运行在任何 PHP 版本之外的 PHP 版本8.0 高达 99.5%:

WordPress 版本使用情况

按版本划分的 WordPress 使用统计数据。 图片来源:WordPress

因此,针对全球受众的 WordPress 主题和插件很可能会使用旧版本的 PHP 进行编码,以增加其可能的覆盖范围。 多亏了转译,这些可以使用 PHP 8.0 进行编码,并且仍会针对较旧的 PHP 版本发布,从而针对尽可能多的用户。

事实上,任何需要支持除最新版本以外的任何 PHP 版本(即使在当前支持的 PHP 版本范围内)的应用程序都可以受益。

Drupal 就是这种情况,它需要 PHP 7.3。 由于转译,开发人员可以使用 PHP 8.0 创建公开可用的 Drupal 模块,并使用 PHP 7.3 发布它们。

另一个示例是为由于某种原因而无法在其环境中运行 PHP 8.0 的客户创建自定义代码时。 尽管如此,由于转译,开发人员仍然可以使用 PHP 8.0 编写他们的可交付成果,并在这些遗留环境中运行它们。

何时转译 PHP

PHP 代码始终可以被转译,除非它包含某些 PHP 功能,而这些功能在以前的 PHP 版本中是没有的。

PHP 8.0 中引入的属性可能就是这种情况:

#[SomeAttr]
function someFunc() {}

#[AnotherAttr]
class SomeClass {}

在前面使用箭头函数的例子中,代码可以被转译,因为箭头函数是语法糖。 相比之下,属性会创建全新的行为。 这种行为也可以在 PHP 7.4 及以下版本中重现,但只能通过手动编码,即不能根据工具或流程自动进行(AI 可以提供解决方案,但我们还没有)。

用于开发用途的属性,例如 #[Deprecated], 可以像删除联合类型一样删除。 但是在生产中修改应用程序行为的属性不能删除,也不能直接转换。

截至今天,没有任何转译器可以采用具有 PHP 8.0 属性的代码并自动生成其等效的 PHP 7.4 代码。 因此,如果您的 PHP 代码需要使用属性,那么对其进行转译将是困难的或不可行的。

可以转译的 PHP 特性

这些是 PHP 7.1 及更高版本的功能,目前可以转译。 如果您的代码只使用这些功能,您可以确信您的转译应用程序将正常工作。 否则,您需要评估转译的代码是否会产生故障。

WordPress花园建议你也读一下这篇文章  如何检查和更新您的 WordPress PHP 版本(2021)

PHP 转译器

目前,有一种用于转译 PHP 代码的工具:Rector。

Rector 是一个 PHP 重构器工具,它根据可编程规则转换 PHP 代码。 我们输入源代码和要运行的规则集,Rector 将转换代码。

Rector 通过命令行操作,通过 Composer 安装在项目中。 执行时,Rector 将输出转换前后代码的“差异”(绿色添加,红色删除):

来自 Rector 的“diff”输出

转译到哪个版本的 PHP

要跨 PHP 版本转换代码,必须创建相应的规则。

今天,Rector 库包含了在 PHP 8.0 到 7.1 范围内转换代码的大部分规则。 因此,我们可以可靠地将 PHP 代码转换为 7.1 版。

还有一些从 PHP 7.1 到 7.0 以及从 7.0 到 5.6 的转换规则,但这些规则并不详尽。 完成它们的工作正在进行中,因此我们最终可能会将 PHP 代码转换为 5.6 版。

转译与向后移植

向后移植类似于转译,但更简单。 向后移植代码不一定依赖于语言的新功能。 相反,只需从新版本的语言中复制/粘贴/改编相应的代码,就可以向旧版本的语言提供相同的功能。

例如,函数 str_contains 在 PHP 8.0 中引入。 PHP 7.4 及以下版本的相同功能可以像这样轻松实现:

if (!defined('PHP_VERSION_ID') || (defined('PHP_VERSION_ID') && PHP_VERSION_ID < 80000)) {
  if (!function_exists('str_contains')) {
    /**
     * Checks if a string contains another
     *
     * @param string $haystack The string to search in
     * @param string $needle The string to search
     * @return boolean Returns TRUE if the needle was found in haystack, FALSE otherwise.
     */
    function str_contains(string $haystack, string $needle): bool
    {
      return strpos($haystack, $needle) !== false;
    }
  }
}

因为向后移植比转译更简单,所以只要向后移植完成工作,我们就应该选择这种解决方案。

关于 PHP 8.0 到 7.1 之间的范围,我们可以使用 Symfony 的 polyfill 库:

这些库向后移植以下函数、类、常量和接口:

转换后的 PHP 示例

让我们检查一些已转译的 PHP 代码示例,以及一些正在完全转译的包。

PHP代码

match 表达式是在 PHP 8.0 中引入的。 此源代码:

function getFieldValue(string $fieldName): ?string
{
  return match($fieldName) {
    'foo' => 'foofoo',
    'bar' => 'barbar',
    'baz' => 'bazbaz',
    default => null,
  };
}

…将被转换为等效的 PHP 7.4 版本,使用 switch 操作员:

function getFieldValue(string $fieldName): ?string
{
  switch ($fieldName) {
    case 'foo':
      return 'foofoo';
    case 'bar':
      return 'barbar';
    case 'baz':
      return 'bazbaz';
    default:
      return null;
  }
}

PHP 8.0 中还引入了 nullsafe 运算符:

public function getValue(TypeResolverInterface $typeResolver): ?string
{
  return $this->getResolver($typeResolver)?->getValue();
}

转译后的代码需要先将操作的值赋给一个新的变量,以避免两次执行操作:

public function getValue(TypeResolverInterface $typeResolver): ?string
{
  return ($val = $this->getResolver($typeResolver)) ? $val->getValue() : null;
}

PHP 8.0 中也引入了构造函数属性提升功能,允许开发人员编写更少的代码:

class QueryResolver
{
  function __construct(protected QueryFormatter $queryFormatter)
  {
  }
}

在为 PHP 7.4 转译它时,会生成完整的代码段:

 class QueryResolver
 {
  protected QueryFormatter $queryFormatter;

  function __construct(QueryFormatter $queryFormatter)
  {
    $this->queryFormatter = $queryFormatter;
  }
}

上面转译的代码包含类型化属性,这些属性是在 PHP 7.4 中引入的。 将该代码转换为 PHP 7.3 将它们替换为 docblocks:

 class QueryResolver
 {
  /**
   * @var QueryFormatter
   */
  protected $queryFormatter;

  function __construct(QueryFormatter $queryFormatter)
  {
    $this->queryFormatter = $queryFormatter;
  }
}

PHP 包

正在为生产转译以下库:

WordPress花园建议你也读一下这篇文章  什么是 WordPress 以及它的用途是什么? 初学者指南 (2021)

转译 PHP 的优缺点

转译 PHP 的好处已经描述过:它允许源代码使用 PHP 8.0(即 PHP 的最新版本),该版本将被转换为 PHP 的较低版本,用于生产在遗留应用程序或环境中运行。

这有效地使我们能够成为更好的开发人员,生成更高质量的代码。 这是因为我们的源代码可以使用 PHP 8.0 的联合类型、PHP 7.4 的类型化属性以及添加到每个新版本 PHP 中的不同类型和伪类型(mixed 从 PHP 8.0 开始, object 来自 PHP 7.2),以及 PHP 的其他现代功能。

使用这些特性,我们可以更好地捕捉开发过程中的错误并编写更易于阅读的代码。

现在,让我们来看看缺点。

它必须被编码和维护

Rector 可以自动转换代码,但该过程可能需要一些手动输入才能使其与我们的特定设置配合使用。

第三方库也必须被转译

每当转换它们产生错误时,这就会成为一个问题,因为我们必须深入研究它们的源代码以找出可能的原因。 如果问题可以解决并且项目是开源的,我们将需要提交拉取请求。 如果库不是开源的,我们可能会遇到障碍。

当代码无法转译时,Rector 不会通知我们

如果源代码包含 PHP 8.0 属性或任何其他无法转译的功能,我们将无法继续。 然而,校长不会检查这个……

营销型WordPress外贸多语言独立站建设+谷歌SEO优化+谷歌关键字广告投放,就找WP花园!深圳公司,技术实力雄厚,用效果说话!详情咨询info@wordpresshy.com

海外社媒SNS代运营Tiktok代运营公司
Revive Old Posts