最佳PHP代码审查关键原则与实践技巧(作者:Tinywan)

2024-05-07 09:49:34
lujie
  • 访问次数: 715
  • 注册日期: 2021-12-14
  • 最后登录: 2024-05-21
  • 我的积分: 2018
  • 门派等级: 无门派

概述

代码审查有时会让人觉得有点乏味。但是它们对于创建工作良好、易于使用并且不会引起安全问题的PHP应用程序来说是绝对必要的。好消息呢?有一种方法可以使代码审查有效。让我们分解一下在审查PHP代码时要寻找的关键内容。

核心原则

1. 功能检查:代码是否完成了它的工作?

代码审查最重要的方面是确保代码实现了其预定目的。重点关注代码逻辑,从接收输入到产生输出的执行流程。检查是否有不合逻辑的步骤、错误的计算,或者流程可能会意外停止的地方。
  • 检查输入:代码是否正确处理了它可能接收到的所有类型的数据?这包括用户输入、数据库数据或来自外部系统的信息。
  • 检查输出:验证代码产生的结果是否正确,并且格式符合预期。输出数据是否符合要求?
彻底的测试是确保功能的关键。单元测试帮助我们系统地检查具有不同输入变量的代码的各个组件,确保代码在所有情况下都按预期运行。

在这个步骤中,我发现能够将代码发布到审查应用程序或暂存服务器,并确认我在代码审查中的发现及其实际工作方式是很有帮助的。对于棘手的部分,我也倾向于搜索添加的单元测试。如果它们丢失了,请作者添加它们可能是一个好主意。

2. 代码功能:是否按设计工作?

在一个可靠的代码审查的核心,我们需要回答一个基本的问题:这些代码做了它应该做的事情吗?开始直接将代码与项目的需求或规范进行比较。您是否已实现所有必要的功能?是否有不正确的行为或缺少任何东西?接下来,仔细地逐步执行代码的逻辑。执行是否遵循从接收到的输入到最终输出的合理路径?寻找任何无意义的分支(比如总是为假的if语句)、无限循环或潜在的崩溃。

检查代码如何处理所有形式的输入。它是否可以处理不同的用户条目、从数据库中提取的各种数据,或者来自另一个系统的信息?同样重要的是,输出是否正确,格式是否正确,并与应用程序的其他部分预期的内容保持一致?

技术提示:不要只是通过点击应用程序来测试。虽然开发人员承担编写单元测试的主要责任,但不要低估在代码审查期间批判性眼光的价值。

  • 缺少测试:是否存在没有相应单元测试的代码块?
  • 边缘用例:测试是否只覆盖预期的场景,还是包括意外的输入和边界条件?
  • 测试质量:测试是否写得很好,它们是否清楚地声明了预期的结果?
在检查时,想象一下用户可能故意(或意外)尝试破坏代码的方式。你能给它输入奇怪的输入,引起不寻常的事件序列,或者使它过载吗?弹性代码应该优雅地处理这些场景。熟练使用像Xdebug这样的调试工具。它允许您暂停代码执行,逐行单步执行,并在事情发生变化时仔细检查变量的值。对于前端代码,我喜欢考虑可能出现的不同UI状态。

一些关键的状态包括空状态,加载状态和错误状态,但重要的是要进一步:
  • 部分加载状态:数据在逐步加载时如何显示?UI的不同部分是否有清晰的加载指示器?
  • 输入验证状态:UI如何立即传达表单验证的成功或失败(例如,内联错误消息)?
  • 成功状态:在一个动作之后(例如,提交一份表格),成功是如何传达的?
  • 交互状态:元素是否提供悬停、聚焦或活动状态的视觉反馈?

3. 代码可读性:你能读懂它吗?

可读的代码对于可维护性和协作是必不可少的。让我们把重点放在使您的代码易于人类和机器解析。从严格遵守PSR-1和PSR-12等编码标准开始。这些标准为PHP代码建立了一种通用语言,定义了缩进、命名约定、文件组织等规则。

通过遵循标准,您的代码变得可预测和一致,减少了阅读者的认知负担。PSR等社区标准最大限度地减少了新加入项目的开发人员的学习曲线,并提高了与不同开发工具的兼容性。

在代码审查期间,仔细评估变量和函数命名。这些名称是否清楚地表达了它们的目的,避免了单字母变量、不必要的缩写或模糊的术语?命名良好的元素有助于自文档化的代码,最大限度地减少了对解释性注释的需求。如果有注释,它们是否专注于解释逻辑或设计选择背后的“为什么”,而不是简单地重复代码的功能?

如果代码感觉很复杂,建议作者重构。这可能涉及提取方法,使用更具描述性的变量名,或为清晰起见重新构造代码块。强调长期可维护性的重要性,即使目前需要一些额外的努力。

使用链接器(如PHPCS)和静态分析工具(如PHPStan)作为审查过程的一部分。这些工具有助于执行标准,捕捉潜在的问题,并促进一致的可读性。寻找代码和已建立的标准之间的不匹配,作为潜在的改进领域。

如果您发现自己在评审过程中很难理解代码流,这就强烈地表明将来的可维护性将是一个挑战。不要犹豫,向作者提出这一点-合作讨论往往可以发现更好的解决方案或澄清潜在的逻辑。

除了格式和命名,严格遵守项目或公司特定的编码规则。这些内容涵盖了命名空间、代码组织和架构模式等方面。虽然自动化工具可以捕获许多违规行为,但在审查过程中要保持警惕,以发现工具可能遗漏的潜在问题。这确保了整个代码库的一致性。

4. 安全性

Web应用程序是攻击的主要目标。在PHP世界中,安全的代码审查会特别关注一些关键领域。

首先,永远不要相信来自外部来源的数据 处理所有用户输入(表单提交、URL参数等)潜在的恶意使用PHP内置的过滤器函数(filter_var,filter_input)去除危险字符(例如,<script>标签以防止XSS)并执行规则以确保输入与您期望的匹配(例如,正确的电子邮件格式或有效的数字范围)。

为了保护您的应用程序免受臭名昭著的SQL注入漏洞的影响,请避免直接将用户输入连接到SQL查询中。相反,依赖于mysqli或PDO准备语句(或者更好,在数据库抽象层[DBAL]或一些好的ORM上)。它们清楚地将SQL结构与用户提供的数据分开,允许数据库安全地处理数据并消除SQL注入尝试。删除危险字符(例如,<script> 标签以防止XSS)并强制执行规则以确保输入符合你的期望。

最后,小心处理错误。避免向用户显示原始错误消息(数据库错误、堆栈跟踪),因为它们可能会泄露敏感的系统信息。相反,将错误记录到一个文件中,供开发人员进行故障排除,确保这些日志本身受到保护,不受未经授权的访问。当出现错误时,向用户显示通用的、有帮助的错误消息,并记录详细信息以进行内部调试。在我们的例子中,我们主要使用Monolog并将日志转发到DataDog或NewRelic等工具。我们也总是有一个哨兵实例连接,以收集更多的信息的问题。

虽然现代框架提供了内置的安全功能,但在代码审查期间确保其正确实现至关重要。密切关注这些方面:
  • 输入清理:代码是否仔细地过滤和验证来自用户的任何数据(表单、URL参数等)?寻找特定于框架的输入清理函数或方法。
  • 预处理语句:数据库查询是否始终使用预处理语句构建?检查框架方法,这些方法有助于防止SQL注入。
  • 错误处理:代码是否避免向用户暴露原始错误消息或堆栈跟踪?是否在内部记录错误,以便开发人员进行故障排除?在出现故障时,是否有用户友好的后备机制?

5. PHP性能优化

执行缓慢的代码会让用户感到沮丧,并且可能会耗尽服务器资源。一个全面的代码审查应该始终考虑性能优化,特别是关注以下方面:

  • 更智能的算法:你构建代码的方式对速度有很大的影响。分析您的核心算法,并寻找使用更有效数据结构的机会(例如,考虑哈希表而不是用于搜索的嵌套循环)。熟悉大O表示法有助于理解代码的效率如何随着较大的数据集而扩展。
  • 数据库交互:对数据库的每个查询都会增加开销。通过使用缓存技术(Memcached,Redis)将频繁访问的数据存储在内存中,减少不必要的数据库调用。当你确实需要查询时,优化你的SQL:适当地使用索引,避免获取比你需要的更多的数据,并注意复杂的连接可能会减慢速度。在开始使用缓存之前,首先关注索引和查询优化。
  • 寻找瓶颈:不要盲目优化!使用像Blackfire这样的分析工具来精确测量你的应用程序在哪里花费了大部分时间。这将精确定位最需要注意的函数或数据库查询。Blackfire提供了对执行时间、函数调用和内存使用的宝贵见解。
技术说明
  • 过早的优化是一个陷阱:首先关注干净的、功能性的代码。过早地过度优化会使代码更难阅读。
  • 缓存有多种形式:根据应用程序的需要,在内存缓存、基于文件的缓存甚至HTTP缓存之间进行选择。
  • 数据集越大,算法的影响就越大:对小规模数据运行良好的代码可能会随着输入大小的增加而爬取。
请特别注意数据库迁移。密切关注数据库迁移,同时考虑代码性能和迁移过程本身。大型迁移可能需要相当长的时间(甚至可能需要几分钟),因此提前了解潜在影响至关重要。

代码评审注意事项

虽然彻底的依赖审计超出了典型的代码审查范围,但以下是需要注意的关键事项:

  • 严重过时的软件包:注意已安装的软件包与其最新版本之间的任何主要版本差异。这可能意味着潜在的兼容性问题或安全风险。
  • 漏洞警报:如果您使用Snyk或Dependabot等工具,请检查它们是否标记了项目依赖项中的任何已知漏洞。
  • 版本含义:建议软件包更新时,请注意语义版本控制(主要.次要.补丁),因为主要更新可能会有破坏性的更改。
  • 公司标准:一些组织有关于依赖关系更新的特定政策,审阅者应该熟悉这些政策。
  • 审查范围:如果时间允许或者安全性是一个关键问题,使用可验证性检查工具进行简短的依赖性扫描可能是代码审查的一个有价值的补充。

数据库优化和安全

始终确保数据库查询一致地使用预处理语句,以减轻SQL注入风险。使用与数据库集成的分析工具(例如,MySQL的慢速查询日志)或Blackfire/New Relic等扩展来识别最有效的优化。注意索引-确保频繁查询的列上存在适当的索引,特别是对于具有多列搜索条件的表。

错误处理

定义创建错误层次结构的自定义异常类(例如:DatabaseException、ValidationException)。这种方法可以在整个代码库中实现粒度错误处理。策略性地使用不同的日志级别(调试、信息、警告、错误)。

适当地配置日志记录工具,以根据严重性进行存储或发出警报。最后,仔细考虑显示给用户的错误消息。这些消息应该清楚地引导用户找到解决方案,而不会泄露敏感的系统细节。

由于信息有限,用户报告的网络安全问题可能很棘手。这就是为什么明确的错误消息和详细的日志是必不可少的。它们为您提供了快速查明问题和改善用户体验所需的线索。

将代码评审作为一种习惯

代码审查不应该被看作是一次性的苦差事,也不应该被看作是简单地发现bug的一种方式。通过将它们作为开发过程中的常规实践,您将不断提高PHP代码库的质量。每一次评审会议都能构建技术知识并加强团队内部的协作。

代码审查也是在团队中传递知识的好方法。不仅编写任务的开发人员知道它是如何实现的,而且进行代码审查的人也会对它有很好的理解。在我们的例子中,我们确保添加,删除或更改的每一行都至少由另一个人审查。

请记住,干净、安全和结构良好的代码不仅仅是美学。它节省了调试时间,降低了漏洞的风险,并允许您的应用程序更优雅地扩展。让代码审查成为你工作流程中不可协商的一部分。随着时间的推移,这些好处将变得更加复杂,导致更健壮,更容易维护和更成功的PHP项目。


——————————————————

原文作者:Tinywan

原文链接:https://mp.weixin.qq.com/s/Rh4Jx15fRNkGQX8qfbPuBg

原文出处:公众号 开源技术小栈


声明:本文系转载,文章版权属于原作者,如有疑问请联系删除。

lujie 最后编辑, 2024-05-07 10:15:48