抢先验证或异常处理?

时间:2012-10-25 14:27:13

标签: php validation exception architecture exception-handling

我试图在两种关于数据验证的模式之间做出决定:

  1. 尝试遵循标称工作流程并捕获我的模型和服务抛出的异常:唯一/外部约束违规,空字段,无效参数等...(!! I只抓住我知道应该的例外情况。

    • 专业人士:我的控制器和服务中编写的代码很少:我只需处理异常并将其转录为用户可理解的消息。 代码非常简单易读

    • 缺点:我需要编写特定的异常,有时可能会有很多不同的异常。我还需要捕获并解析数据库异常(约束违规等等)的泛型PDO / Doctrine异常,以将它们转换为有意义的异常(例如:DuplicateEntryException)。我也无法绕过某些验证:假设我的模型的一个对象被标记为已锁定:尝试删除它会引发异常。但是我可能想强制删除它(例如使用确认弹出窗口)。我不能在这里绕过这个例外。

  2. 使用代码和数据库查询测试并预先验证所有内容。例如,在将其设置为模型中的属性之前,我将测试某些内容不为null并且是一个整数。或者我将进行数据库查询以检查我是否不会创建重复的条目。

    • 专业人士:无需编写特定的异常,因为我预先验证了所有内容,所以我不应该做很多try / catch。如果我愿意,我可以绕过一些验证

    • 缺点:在控制器,服务和模型中编写大量测试和验证。我将执行更多查询(验证部分)。 数据库已经对外键,唯一约束,而不是空列进行验证 ...我不应该忽略它并自己重新编码。这也会导致非常无聊的代码

  3. 我宁愿使用一种模式或另一种模式,而不是混合模式,以使事情尽可能简单。

    第一个解决方案在我看来似乎是最好的,但我担心它可能是某种反模式?或者可能在其理论上的简单性背后隐藏着很难处理的情况?

1 个答案:

答案 0 :(得分:2)

我建议数据验证应该在应用程序的周边进行。也就是说,应该检查所有进入的数据,以确保它符合您的期望。一旦允许进入应用程序,它就不再被验证,但它总是根据上下文(数据库,电子邮件等)进行转义。这使您可以将所有验证保持在一起并避免可能的重复验证工作(很容易以及两个使用它的模型可以对数据进行两次验证的例子。)Joe Armstrong在他关于Erlang的书中推广了这种方法,他为telcom工作站编写的软件运行多年而没有重新启动,所以它似乎运行良好: )

此外,模型期望并不总是与特定界面建立的期望完全一致(可能表格只显示潜在选项的子集,或者界面可能是美国各州和模型商店的下拉来自许多不同国家的状态等。)有时,复杂的接口可以以增强用户体验的方式集成若干不同的模型对象。虽然对用户很好,但使用异常方法的这些模型的交互可能非常难以处理,因为一些输入可能是混合输入,两种模型都不能单独验证。您始终希望确保验证首先符合UI的期望,而第二种方法允许您在最复杂的界面中执行此操作。

此外,异常处理在周期方面相对昂贵。验证问题可能非常频繁,我会尽量避免处理问题这么昂贵的操作而不是频繁发生。

最后,模型并不需要进行一些验证,但它可以防止攻击。虽然您可以将其添加到模型中,但添加的功能可能会使模型代码快速混乱。

因此,在这两种方法中,我建议采用第二种方法,因为:

  1. 您可以为自己的应用制作清晰的边界。
  2. 所有验证都在一个地方,可以共享。
  3. 如果两个或多个模型使用相同的输入,则不会重复验证。
  4. 模型可以专注于他们擅长的领域:将抽象实体的知识映射到应用程序状态。
  5. 即使是最复杂的用户界面也可以进行适当的验证。
  6. 抢占可能会更有效率。
  7. 不能真正属于任何模型的以安全为中心的验证任务可以干净地添加到应用程序中。