抢先验证或异常处理?

Mat*_*oli 8 php architecture validation exception-handling exception

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

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

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

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

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

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

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

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

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

Ada*_*onR 2

我建议数据验证应该在应用程序的外围进行。也就是说,应该检查传入的任何数据以确保其符合您的期望。一旦允许进入应用程序,它就不再被验证,但它总是根据上下文(数据库、电子邮件等)进行转义。这使您可以将所有验证放在一起,并避免潜在的重复验证工作(很容易Joe Armstrong 在他关于 Erlang 的书中推广了这种方法,他为电信站编写的软件可以运行多年而无需重新启动,因此它似乎运行良好: )

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

此外,异常处理在周期方面相对昂贵。验证问题可能非常频繁,并且我会尝试避免使用如此昂贵的操作来处理可能会非常频繁的问题。

最后,一些验证对于模型来说并不是真正必要的,但它是为了防止攻击。虽然您可以将其添加到模型中,但添加的功能很快就会使模型代码变得混乱。

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

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