Symfony 6: PHP 8 Native Types & 为什么我们需要你

Symfony 2.0 以来,Symfony 的最大变化即将到来,这是一个非常激动人心的时刻:Symfony 6 在其所有可能的方法上都具有原生 PHP 类型。这将极大地推动 PHP 开源社区中的类型安全!Nicolas和 Alexander已经断断续续地工作了 2 年,以创造可能的最佳升级体验。
现在,距离稳定版发布还有 2.5 个月,是大放异彩的时候了!特别是如果您维护任何开源项目(甚至没有直接链接到 Symfony),我们很乐意听取您的意见,以确保升级不会非常困难。

从 Symfony 5.4 开始,调试类加载器(在开发/测试环境中的 Symfony 应用程序中使用)将检查返回类型的兼容性,并在方法不兼容时向您发出警告。更重要的是……它可以自动为您修复!在 Symfony 文档中阅读有关此功能的更多信息。

Symfony 应用程序升级计划

开源包和应用程序的升级计划略有不同。如果您使用 Symfony 框架(或仅使用某些组件)构建应用程序,本节将描述您的升级计划。

为使这种体验尽可能顺畅而创建的技术和工具是全新的。请立即安装 5.4-dev 并让我们知道任何问题


$ composer config minimum-stability dev
# now, modify all Symfony constraints to "^5.4" in "composer.json", then:
$ composer update 'symfony/*'

升级到 Symfony 5.4 时

首先,升级到 Symfony 5.4。除了修复所有“正常”弃用之外,您还需要修复一些类型声明。

在 PHP 中,当父声明(还)没有定义返回类型时,可以定义它:

1
2
3
4
5
6
7
8
9
10
11
12
13
interface UserInterface
{
    public function getRoles();
}

class User implements UserInterface
{
    // valid!
    public function getRoles(): array
    {
        // ...
    }
}

另一方面,如果你的父级定义了返回类型,你必须定义一个返回类型(记住,Symfony 6 将定义返回类型!)。这意味着 5.4 是你为所有方法添加返回类型的时候了(尤其是那些覆盖或实现来自 Symfony 的方法)。

Symfony 在symfony/error-handler组件中提供了一个小实用程序 来自动添加所需的返回类型。首先,使用 Composer 生成应用程序的完整类图。然后,运行该实用程序:


# (1) Make sure "exclude-from-classmap" is not set in your "composer.json"

# (2) Generate the classmap ("-o" is important!)
$ composer dump-autoload -o

# (3) Run the patch script
$ ./vendor/bin/patch-type-declarations

一旦你修复了它们(运行上面的这个脚本将为你完成所有的工作),你就可以升级到 Symfony 6!

使用 Symfony 6.x 时

升级到 Symfony 6.0 后,就可以开始添加参数类型了。参数类型兼容性与返回类型相反:如果父级已经设置了类型,子级可能不会设置类型,但子级不能在父级之前设置类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
interface FormTypeGuesserInterface
{
    public function guessType($class, $property);
}

class CustomTypeGuesser implements UserInterface
{
    // error!
    public function guessType(string $class, string $property)
    {
        // ...
    }
}

因此,您不能在 5.4 中添加这些参数类型。

Symfony Bundle 维护者兼容性计划

不幸的是,开源维护者在添加返回类型时会遇到更多麻烦。这是因为您可能关心不破坏向后兼容性。而且,如前所述,定义返回类型意味着所有覆盖/实现该方法的用户也必须定义它。

记录返回类型

首先,您只能在安全方法上添加返回类型。这些方法不应由包的用户扩展。Symfony 的补丁工具将安全方法定义为:

  • Tests命名空间中
  • final@final(或其类)
  • @internal(或其类)
  • 是 private

使用force=1仅斑块类型为这些安全的方法:


# you can set the minimum PHP version, e.g. "static" won't be added
# as a return type for 7.4
$ SYMFONY_PATCH_TYPE_DECLARATIONS="force=1&php=7.4" ./vendor/bin/patch-type-declarations

现在,您必须检查是否有任何方法会在 Symfony 6 中产生错误。最快的方法是再次运行相同的脚本。输出中的任何弃用都是不兼容的方法。

如果您没有看到任何弃用:恭喜!您与 Symfony 6 兼容,并且可以允许^6.0您的 Symfony 依赖项而不必破坏用户的兼容性。

修复所有返回类型

一些包可能会发现它们需要向可能被覆盖或实现的方法添加返回类型。由于这会导致向后兼容性中断,因此您可能不想在次要版本中执行此操作。

相反,请确保使用@returnPHPDoc正确记录正确的返回类型。这将为您的用户创建有用的弃用,让他们知道他们必须更新他们的 PHP 返回类型。补丁脚本可以为从第三方类/接口实现/覆盖的方法添加此 PHPDoc:


$ SYMFONY_PATCH_TYPE_DECLARATIONS=force=phpdoc ./vendor/bin/patch-type-declarations

在所有弃用的次要版本之后,您可以安全地在下一个主要版本中添加所有缺少的返回类型。

这个过程的缺点是你不能支持 Symfony 6,直到你自己的包的这个主要版本。请确保您继续阅读以了解如何甚至可以避免这种情况!

我们需要你让每个人的生活更美好

正如您在这篇文章中看到的,添加返回类型会对社区产生相当大的影响。某些返回类型可能会导致许多包发布新的主要版本,这可能会扰乱任何路线图或其他流程。

这就是为什么我们欢迎您报告任何导致您破坏包兼容性的返回类型弃用。您可以在此 GitHub 问题这样做 。

我们不做任何承诺,但根据反馈,我们可能会将一些返回类型推迟到 Symfony 7(给您 2 年的时间来发布新的主要版本)。我们已经为 Symfony 包中的一些常见方法(例如Command::execute(): int和 VoterInterface::vote(): int)这样做了。

带回家的

via https://wouterj.nl/2021/09/symfony-6-native-typing

Symfony 6: PHP 8 Native Types & 为什么我们需要你
标签: