本文探讨防御式编程在PHP开发中的重要性,并提供一些关键策略以提升应用的健壮性和效率。防御式编程并非为了避免测试驱动开发,而是为了在问题发生前预见并规避潜在的故障点。
核心要点:
防御式编程的定义:
防御式编程,简单来说,就是以预测潜在故障点为目的进行编程。目标是在这些问题发生之前规避它们。
许多人反对防御式编程,但这往往是因为他们所见到的某些防御式编程方法。防御式编程不应被视为避免测试驱动开发或仅仅是弥补故障的一种方式。
“快速失败”不应被视为防御式编程的对立面。两者都属于同一范畴。这些方法如果不是为了预测程序可能失败,并预防或妥善处理这些失败,那又是什么呢?
快速失败,大声报错
简单来说,“快速失败,大声报错”意味着当发生错误时,它会尽早发生,并向相关人员发出警报,而不是在错误状态下默默继续运行,这可能会导致更多问题。
这种方法在处理用户输入或来自脚本、模块或系统外部(例如通过API)的输入时最为有用。一个应用场景是检查传递给函数的无效值或数据类型。
function thisTestFunction($testInt) { if (!is_int($testInt)) { // 执行某些操作 } }
一些程序员在使用“快速失败”方法时的一个错误是,只是简单地向用户抛出异常和错误,而没有为处理它们做好适当的准备。您不希望普通用户因您的错误消息而感到担忧或困惑。更重要的是,您不希望恶意用户从显示给他们的信息中学习到任何东西。向用户显示有帮助的消息,记录您的错误,并执行任何其他需要作为该异常结果的任务。您不希望只是快速失败,您还需要大声(立即知道存在问题)和安全(不要让您糟糕的异常处理或完全缺乏异常处理导致更多安全问题)。
输入验证
有很多方法可以安全地验证用户输入。
类型转换是一种有趣的“验证”用户输入的方法。有时它看起来像这样:
function thisTestFunction($testInt) { if (!is_int($testInt)) { // 执行某些操作 } }
它没有使用其他方法来避免跨站点脚本攻击,而是简单地捕获、类型转换并赋值。这仅在您有预期类型并且该类型的任何值都是安全的情况下才有效(否则,您还需要检查适当的整数值)。我认为这种方法的问题(在大多数情况下)是您并没有真正检查输入,而只是强制它成为它应该成为的样子。这可能会产生意想不到的后果。相反,更好的方法可能是使用filter_input()
来检查适当的值。
$member->property = (int)$_GET['property'];
在现代PHP中使用原生filter_input
函数有很多好处,您可以在上述文章或php.net上了解更多信息。
防止比较中的意外赋值
这是一个简单且经常被注意到的防御式编程原则。在比较方式上进行简单的更改可以产生巨大的影响。考虑以下情况:
$member->property = filter_input(INPUT_GET, 'property', FILTER_VALIDATE_INT); if (false === $member->property) { throw new Exception('Property was not an int'); }
这是一个相对正常的比较,对吧?但是,如果您不小心使用“=”而不是“==”(或者在大多数情况下,更好的“===”)会发生什么?键盘上手指的简单滑动?健忘,也许?突然之间,您的比较总是、在所有情况下都为真。除非您的IDE警告您这一点,否则您需要多长时间才能发现它?在某些情况下,这可能是一段时间内的静默错误。但是,有一种极其简单的方法可以防止这种情况:
if ($member->property == 12345) { // 执行很酷的操作 } else { // 不执行任何有趣的操作 }
现在,如果您不小心使用一个等号,错误就不会是静默的。显然,这种情况可能不会经常发生,它可能被您的测试所减轻,并且在所有情况下都不实用,尤其是在进行变量到变量的比较时。但如果您倾向于发生这种情况,这仍然不是一个坏主意。
处理Try/Catch和异常
try/catch语句是PHP开发人员中的另一个热门话题。让我们首先快速了解一下我们正在讨论的内容。
if (12345 == $member->property) { // 执行很酷的操作 } else { // 不执行任何有趣的操作 }
防御式编程的一个知名工具是try/catch语句和Exception类。当正确使用时,它们非常适合捕获和记录错误。一个优秀的程序员会使用try/catch语句来预测可能导致中断正常流程的错误或其他情况。当这些异常发生时,必须以适当的方式处理它们。如果需要,应用程序的用户应该收到尽可能有用的合理错误消息,而不会泄露敏感信息。应用程序的管理员应该收到详细的警报和/或日志。未经处理或被忽略的异常会忽略“大声报错”的建议,并可能允许程序在本质上处于静默错误状态一段时间,这对任何相关人员都不利。
事务
事务是数据库的一项功能,它允许将查询组合在一起,以便如果一个查询失败,所有查询都失败。这是ACID的实现,您可以在此处阅读更多相关信息。其思想是,将多个查询组合成一个过程有时可能是一种更安全、更稳定的解决方案,尤其是在查询相互依赖的情况下。PHP开发人员经常完全忽略事务,或假设它们是不必要的,但在与数据库交互时,一些防御式编程可以大有帮助。事务在本文中进行了更深入的讨论,但简而言之,事务允许您运行MySQL更新,然后在实际提交结果之前检查结果。如果您使用的是PDO(您应该使用),您可以使用PDO方法开始事务、提交结果以及回滚。除了上述关于事务的概述之外,还可以通过本深入指南进一步研究它们。
结论
这些只是一些通用的技巧。显然,它们每个都有其用途,并且每个都有其不适用的显著情况。但是,如果您将这些概念融入到您的日常开发制度中,它可以提高您工作的效率。虽然这通常是一个更适用于目前正在学习PHP的开发人员的话题,但对于每个人来说,它都是对实践的良好回顾。
如果只有一件事被记住,特别是对于较新的开发人员,那就是您应该进行防御式编程——计划可能出现的错误。妥善处理它们。不要让静默错误继续发展。快速失败。测试您的代码。通过构建测试并解决问题,并预测和处理未来问题的健壮应用程序,您可以使您的应用程序更可靠,并有望在幕后帮助创造更好的用户体验。
以上是PHP中防御性编程的更多提示的详细内容。更多信息请关注PHP中文网其他相关文章!