测试迁移并排除故障

在理想的情况下,迁移故障排除工作将在实际迁移到生产环境之前,在暂存服务器或模拟虚拟环境中进行。然而,经验丰富的开发人员都知道,我们需要寄希望于最好的结果,但也要做好最坏的打算!在本节中,我们将介绍容易被忽视的测试和故障排除的其他方面。

在本节中,如果您使用的是 Debian/Ubuntu 或 Red Hat/CentOS/Fedora 安装程序,则可以退出临时 shell。返回本课程使用的 Docker 容器,并打开命令 shell 进入 PHP 8 容器。如果您不确定如何操作,请参阅 第 1 章 "PHP 8 OOP 新特性介绍" 中的 "技术要求" 部分。

测试和故障排除工具

有太多优秀的测试和故障排除工具可供使用,这里就不一一列举了,因此我们重点介绍几款有助于测试和故障排除的开源工具。

使用 Xdebug

Xdebug 是一款提供诊断、剖析、跟踪和分步调试等功能的工具。它是一个 PHP 扩展程序,因此可以在遇到无法轻松解决的问题时提供详细信息。主要网站是 https://xdebug.org/

要启用 Xdebug 扩展,可以像安装其他 PHP 扩展一样安装它:使用 pecl 命令,或从 https://pecl.php.net/package/xdebug 下载并编译源代码。

此外,至少应设置以下 /etc/php.ini 设置:

zend_extension=xdebug.so
xdebug.log=/repo/xdebug.log
xdebug.log_level=7
xdebug.mode=develop,profile

图 11.2 显示了使用 /repo/ch11/php8_xdebug.php 调用的 xdebug_info() 命令的输出结果:

image 2023 11 24 16 28 47 159
Figure 1. Figure 11.2 – xdebug_info() output

现在让我们看看另一种从外部角度检查应用程序的工具。

使用 Apache JMeter

Apache JMeter (https://jmeter.apache.org/) 是一款非常有用的测试网络应用程序的开源工具。它允许你开发一系列模拟浏览器请求的测试计划。您可以模拟数百个用户请求,每个请求都有自己的 cookie 和会话。虽然它主要针对 HTTP 或 HTTPS 而设计,但也能支持其他十几种协议。除了出色的图形用户界面外,它还有一个命令行模式,可以将 JMeter 集成到自动部署流程中。

安装非常简单,只需从 https://jmeter.apache.org/download_jmeter.cgi 下载即可。在运行 JMeter 之前,您必须安装 Java 虚拟机(JVM)。测试计划的执行不在本书的讨论范围之内,但文档内容相当丰富。另外,请记住 JMeter 是为在客户端而非服务器上运行而设计的。因此,如果你想在本书的 Docker 容器中测试网站,你需要在本地计算机上安装 Apache JMeter,然后建立一个指向 Docker 容器的测试计划。通常,PHP 8 容器的 IP 地址是 172.16.0.88。

图 11.3 显示了在本地计算机上运行 Apache JMeter 的打开屏幕:

image 2023 11 24 16 30 46 469
Figure 2. Figure 11.3 – Apache JMeter

通过该屏幕,您可以制定一个或多个测试计划,指明要访问的 URL、模拟 GET 和 POST 请求、设置用户数量等。

如果在尝试运行 jmeter 时遇到此错误:Can’t load library: /usr/lib/jvm/java-11-openjdk-amd64/lib/libawt_xawt.so,请尝试安装 OpenJDK 8。然后,您可以使用前一节中提到的技术在不同版本的 Java 之间进行切换。

现在让我们来看看 PHP 8 升级后 Composer 可能出现的问题。

处理 Composer 的问题

迁移到 PHP 8 后,开发人员面临的一个常见问题是第三方软件。在本节中,我们将讨论与使用流行的 PHP Composer 软件包管理器有关的潜在问题。

可能遇到的第一个问题与 Composer 本身的版本有关。2020 年,Composer 发布了第 2 版。但是,主打包网站 (https://packagist.org/) 上的 30 多万个软件包并没有全部更新到版本 2。因此,为了安装某个软件包,您可能需要在 Composer 2 和 Composer 1 之间切换。每个版本的最新发布信息请点击此处:

另一个更严重的问题与您可能使用的各种 Composer 软件包的平台要求有关。每个软件包都有自己的 composer.json 文件,都有自己的要求。在许多情况下,软件包提供商可能会添加 PHP 版本要求。

问题是,虽然大多数 Composer 软件包现在都能在 PHP 7 上运行,但这些要求是以排除 PHP 8 的方式指定的。PHP 8 更新后,当您使用 Composer 更新第三方软件包时,就会出现错误,更新失败。具有讽刺意味的是,大多数 PHP 7 软件包也能在 PHP 8 上运行!

例如,我们安装了一个名为 laminas-api-tools 的 Composer 项目。在写这篇文章时,虽然软件包本身已经为 PHP 8 做好了准备,但它的一些依赖软件包还没有。在运行安装 API 工具的命令时,会遇到以下错误:

root@php8_tips_php8 [ /srv ]#
composer create-project laminas-api-tools/api-tools-skeleton
Creating a "laminas-api-tools/api-tools-skeleton" project at
"./api-tools-skeleton"
Installing laminas-api-tools/api-tools-skeleton (1.3.1p1)
- Downloading laminas-api-tools/api-tools-skeleton (1.3.1p1)
- Installing laminas-api-tools/api-tools-skeleton (1.3.1p1):
Extracting archiveCreated project in /srv/api-tools-skeleton
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set
of packages.
Problem 1
- Root composer.json requires laminas/laminas-developertools dev-master, found laminas/laminas-developer-tools[devrelease-1.3, 0.0.1, 0.0.2, 1.0.0alpha1, ..., 1.3.x-dev, 2.0.0,
..., 2.2.x-dev] but it does not match the constraint.
Problem 2
- zendframework/zendframework 2.5.3 requires php ^5.5
|| ^7.0 -> your php version (8.1.0-dev) does not satisfy
that requirement.

在刚刚显示的最后一部分输出中,核心问题是其中一个依赖软件包要求 PHP ^7.0。在 composer.json 文件中,这表明了从 PHP 7.0 到 PHP 8.0(包括 PHP 8.0)的版本范围。在这个例子中,使用的 Docker 容器运行的是 PHP 8.1,因此我们遇到了问题。

幸运的是,在这种情况下,我们确信如果这个软件包在 PHP 8.0 中运行,它也应该在 PHP 8.1 中运行。因此,我们只需添加 --ignore-platform-reqs 标志即可。当我们重试安装时,可以从下面的输出中看到,安装成功了:

root@php8_tips_php8 [ /srv ]#
composer create-project --ignore-platform-reqs \
laminas-api-tools/api-tools-skeleton
Creating a "laminas-api-tools/api-tools-skeleton" project at
"./api-tools-skeleton"
Installing laminas-api-tools/api-tools-skeleton (1.6.0)
- Downloading laminas-api-tools/api-tools-skeleton (1.6.0)
- Installing laminas-api-tools/api-tools-skeleton (1.6.0):
Extracting archive
Created project in /srv/api-tools-skeleton
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current
platform.
Package operations: 109 installs, 0 updates, 0 removals
- Downloading laminas/laminas-zendframework-bridge (1.3.0)
- Downloading laminas-api-tools/api-tools-asset-manager
(1.4.0)
- Downloading squizlabs/php_codesniffer (3.6.0)
- Downloading dealerdirect/phpcodesniffer-composer-installer
(v0.7.1)
- Downloading laminas/laminas-component-installer (2.5.0)
... not all output is shown

在刚刚显示的输出中,没有出现平台要求错误,我们可以继续使用应用程序。

现在,让我们把注意力转向单元测试。

使用单元测试

使用 PHPUnit 进行单元测试是确保应用程序在添加新功能或 PHP 更新后运行的关键因素。大多数开发人员都会创建一组单元测试,至少要执行最基本的测试,以证明应用程序的运行符合预期。测试是一个扩展了 PHPUnit\Framework\TestCase 的类中的方法。测试的核心是所谓的断言。

关于如何创建和运行测试的说明超出了本书的范围。不过,您可以在 PHPUnit 主网站 https://phpunit.de/ 上查阅包含大量示例的优秀文档。

PHP 移植后可能遇到的问题是 PHPUnit ( https:// phpunit.de/ )本身可能失效!这是因为 PHPUnit 每年都有一个新版本,与当年的 PHP 版本相对应。旧版本的 PHPUnit 是基于官方支持的 PHP 版本。因此,目前为应用程序安装的 PHPUnit 版本完全有可能是不支持 PHP 8 的旧版本。最简单的解决办法就是使用 Composer 进行更新。

为了说明可能存在的问题,我们假设应用程序的测试目录目前包含 PHP 单元 5。如果我们在运行 PHP 7.1 的 Docker 容器中运行一个测试,一切正常。下面是输出结果:

root@php8_tips_php7 [ /repo/test/phpunit5 ]# php --version
PHP 7.1.33 (cli) (built: May 16 2020 12:47:37) (NTS)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
with Xdebug v2.9.1, Copyright (c) 2002-2020, by Derick
Rethans
root@php8_tips_php7 [ /repo/test/phpunit5 ]#
vendor/bin/phpunit
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.
........
8 / 8 (100%)
Time: 27 ms, Memory: 4.00MB
OK (8 tests, 8 assertions)

但是,如果我们在运行 PHP 8 的 Docker 容器中运行相同的版本,结果就大不一样了:

root@php8_tips_php8 [ /repo/test/phpunit5 ]# php --version
PHP 8.1.0-dev (cli) (built: Dec 24 2020 00:13:50) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.0-dev, Copyright (c) Zend Technologies
with Zend OPcache v8.1.0-dev, Copyright (c),
by Zend Technologies
root@php8_tips_php8 [ /repo/test/phpunit5 ]#
vendor/bin/phpunit
PHP Warning: Private methods cannot be final as they are never
overridden by other classes in /repo/test/phpunit5/vendor/
phpunit/phpunit/src/Util/Configuration.php on line 162
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.
........
8 / 8 (100%)
Time: 33 ms, Memory: 2.00MB
OK (8 tests, 8 assertions)

从输出中可以看到,PHPUnit 本身报告了一个错误。当然,简单的解决办法是在 PHP 8 升级后,还需要重新运行 Composer 并更新与应用程序一起使用的所有第三方软件包。

关于测试和故障排除的讨论到此结束。您现在已经知道在测试和故障排除时还可以使用哪些工具。但请注意,这绝不是一份包含所有测试和故障排除工具的全面清单。还有很多很多,有些是免费开源的,有些是提供免费试用期的,还有更多的只能通过购买获得。

总结

在本章中,你将了解如何使用 "环境 "一词而不是 "服务器",因为如今许多网站都使用虚拟化服务。然后,你了解了在部署阶段使用的三种不同环境:开发环境、暂存环境和生产环境。

接下来,我们介绍了一种能够扫描应用程序代码以查找潜在代码漏洞的自动化工具。正如您在该部分所学到的,断点扫描应用程序可能由一个配置文件、一个扫描类和一个收集文件名的调用程序组成,该配置文件涉及已删除的功能、方法签名的更改、不再产生资源的函数、一组用于复杂用法检测的回调。

接下来,我们向您展示了典型的十二步 PHP 8 迁移过程,以确保在您最终准备升级生产环境时有更大的成功机会。每个步骤的设计都是为了发现潜在的代码断点,并在出错时提供备用程序。您还学会了如何在两种常见平台上安装 PHP 8,以及如何轻松恢复到旧版本。最后,你还了解了许多有助于测试和故障排除的免费开源工具。

总之,在仔细阅读本章并学习了示例之后,你现在不仅能够使用现有的测试和故障排除工具,而且还知道了如何开发自己的扫描工具,从而大大降低 PHP 8 迁移后可能出现代码崩溃的风险。现在,您对迁移到 PHP 8 所涉及的内容也有了很好的了解,可以更顺利地进行迁移,而不必担心失败。您预测和解决迁移问题的新能力将减轻您的焦虑。您还可以期待拥有快乐和满意的客户。

下一章将向您介绍 PHP 编程中令人兴奋的新趋势,它们可以进一步提高性能。