webmozarts / assert

Assertions to validate method input/output with nice error messages.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Custom exceptions

tvdijen opened this issue · comments

Hi,

I'm looking for a way to raise custom exceptions per assertion..
Looking at the code, it currently seems only possible to override Assert::reportInvalidArgument for all assertions..
The only way I see around this is to add an optional argument to every assertion, allowing to pass a custom exception class.. Would you be open for a PR to support this? Or do you see another way to achieve what I'm after?

Currently the way to do this in this library is to overwrite the reportInvalidArgument method as you mentioned.

I'm not 100% sure about adding a new optional argument. I'm not sure if that would be a BC break or not, as that may break users who extend the Assert class and who overwrite some methods.

Depending on the implementation we could work out something.

@tvdijen what would be the use case for custom exceptions?

Well, to me InvalidArgumentException is just too generic.. I work on a library that processes complex XML structures and sometimes an assertion failing means something like 'Protocol violation' (i.e. a missing element) and sometimes it means 'Value is not a valid emailaddress'.. Sometimes we can recover from it and sometimes we can't, but right now I have no way of distinguishing certain types of exceptions, other than catching them all and test exception messages..

But in this case wouldn't more custom validation oriented checks be more appropriate? This library goal was to enable to add guards for things the PHP type system cannot catch. Those guards are the last line of defence that should never be reached.

This is also why it's throwing InvalidArgumentException which derivates from LogicException and not RuntimeException

I see your point, but I think you're missing mine..
This library could work well for both purposes.. Why not use it to cover the business logic checks and replace them with a one-liner as well?

Because usually when you start dealing with validation (your case) instead of assertions, you start to have:

  • laziness (you prefer to provide a maximum of validation errors at once not a fail fast)
  • validation error formatting
  • validation error translation

And suddenly it's a lot more complex.

Another reason is because Assert is a static stateless utility. As soon as you open reportInvalidArgument it no longer is: you have global configuration state. Which also means while you can customize your exception, you don't get to pick where exactly, it's gonna be done globally.

That said: I'm not saying it should be done. I simply want to make clear what it entails, the limitations and the drawbacks and try to see where the line should be drawn.

Actually counter point: isn't it already doable? https://3v4l.org/JVap6
So you can have your "domain/validation assertions" whilst the rest of the application can have regular assertions

I was trying to avoid what you're suggesting, because it means that for every custom exception I would have to create a class extending Assert... That can get out of hand pretty fast.. But I guess it is what it is and I'll go with that!

Those guards are the last line of defence that should never be reached.

I agree with that. But when they are reached how is it an InvalidArgumentException? The library should use a custom exception that can be handled in many ways by end developers. InvalidArgumentException that this library uses collides with other InvalidArgumentException exceptions thrown in unrelated libraries and in projects. A huge mistake.

It's by design: this assert library is here to compensate the typesystem gaps not provide a domain validation. As a result, what you get is a LogicException (InvalidArgumentException being a child of it) as opposed to a RuntimeException.

But as pointed out in #177 (comment), you can if you desire adapt it.

That's not how the original beberlei-lib was designed

But this is not the beberlei lib... One example is the lack of laziness support.

In any case: I already provided an example on how to extend it with minimal efforts. Isn't it [the extension point] good enough for your use case?

Let's not start over the entire discussion...
It's a horrible an excellent design choice and I'm glad to see I'm not alone we all agree on that.

You are free to abstain from commenting if it's to throw degrading comments without any form of constructive argumentation 🙄

@githoober We've created a wrapper for this, should you need this functionality; https://github.com/simplesamlphp/assert