webmozarts / assert

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[feature proposal] How about introduce a static class `Valid` ?

ribeiropaulor opened this issue · comments

I think it would be very useful to have a static class Valid that would have the same methods of Assert, but instead of throwing an exception when the condition is invalid it would return false.

if (!Valid:uuid('test')) {
    return new Response('', 404);
}

Many times I want to integrate this library in contexts - taking advantage of its working validation code - where throwing an exception is not desired.

Do you think would that be useful? Or even pertinent to this library scope?

You could solve this with a try catch, instead of using it within an if statement. The following class would also do the trick. It hints the IDE through the @mixin annotation. I'm not sure how well static analysis tools would handle this.

/**
 * @mixin Assert
 */
class Valid
{
    public static function __callStatic(string $name, array $arguments): bool
    {
        try {
            call_user_func_array([Assert::class, $name], $arguments);
            return true;
        } catch (InvalidArgumentException $e) {
            return false;
        }
    }
}

I'm not too keen on having this code in this code base, as it is a little too much magic.

What could be an option is to change all the methods as follows:

    public static function string($value, $message = '')
    {
        if (!\is_string($value)) {
-            static::reportInvalidArgument(\sprintf(
+           return static::reportInvalidArgument(\sprintf(
                $message ?: 'Expected a string. Got: %s',
                static::typeToString($value)
            ));
        }
    }

This would then allow you to override the reportInvalidArgument method for your class to return something. This however would mean that the happy path returns null. So that may not be the best solution either, what do you think?

@BackEndTea , thanks for replying with suggestions.

I already use something like you suggested.

IMHO, my proposal would simplify the use of the library when Valid was needed instead of Assert. The developer would not have to care about the $message parameter and the intention would become clearer. Moreover, we could improve the messages in some cases like the following stringNotEmpty().

class Valid
{
    public static function string($value)
    {
        return \is_string($value);
    }

    public static function notEq($value, $expect)
    {
        return $expect != $value;
    }

    public static function stringNotEmpty($value)
    {
        return static::string($value) && static::notEq($value, '');
    }
}
class Assert
{
    public static function string($value, $message = '')
    {
        if (!Valid::string($value)) {
            static::reportInvalidArgument(
                \sprintf(
                    $message ?: 'Expected a string. Got: %s',
                    static::typeToString($value)
                )
            );
        }
    }

    public static function notEq($value, $expect, $message = '')
    {
        if (!Valid::notEq($value, $expect)) {
            static::reportInvalidArgument(
                \sprintf(
                    $message ?: 'Expected a different value than %s.',
                    static::valueToString($expect)
                )
            );
        }
    }

    public static function stringNotEmpty($value, $message = '')
    {
        if (!Valid::stringNotEmpty($value)) {
            static::reportInvalidArgument(
                \sprintf(
                    $message ?: 'Expect a not empty string. Got: %s.',
                    static::valueToString($value)
                )
            );
        }
    }
}

Just to be clear, I'm not complaining about the library. I use it every day. As it would not break backwards compatibility, I just thought it would be an improvement.

If you think this suggestion makes sense, I'm willing to help or even implement this feature myself. If you'd rather leave it like it's today, there is no problem either! :-)