A Class to validate password strength What would be the best approach to write this class.

This class validates 3 types of passwords,


Normal
Medium
Strong


Github Link



&lt;?php namespace azi\Rules;


use azi\Arguments;
use azi\Rules\Contracts\RuleInterface;

/**
 * Class Password
 *
 * @package azi\Rules
 */
class Password implements RuleInterface
{
    const NORMAL = 'normal';
    const MEDIUM = 'medium';
    const STRONG = 'strong';

    protected $message = null;

    /**
     * @param $field
     * @param $password
     * @param Arguments $args
     * @return mixed
     */
    public function validate($field, $password, Arguments $args)
    {
        $type = $args-&gt;getVariables();

        if ($type &amp;&amp; $type != self::NORMAL) {
            return $this-&gt;is($type[ 0 ], $password);
        }

        return $this-&gt;isNormal($password);
    }

    /**
     * @param $strength
     * @param $password
     * @return bool
     */
    public function is($strength, $password)
    {
        $method = sprintf("is%s", ucwords($strength));
        return call_user_func([$this, $method], $password);
    }

    /**
     * @param $password
     * @return bool
     */
    public function isNormal($password)
    {
        if (strlen($password) &lt; 8) {
            $this-&gt;message = '{field} must be at least 8 characters long';
            return false;
        }

        if (!preg_match("#[a-zA-Z]#", $password)) {
            $this-&gt;message = '{field} must contain at least one letter';
            return false;
        }


        return true;
    }

    /**
     * Checks a strong password
     *
     * @param $password
     * @return bool
     */
    public function isStrong($password)
    {
        if (!$this-&gt;isMedium($password)) {
            return false;
        }

        if (!preg_match("#[!@\#\$%^&amp;*()_+\-=\[\]{};':\"\\|,.&lt;&gt;\/?]+#", $password)) {
            $this-&gt;message = '{field} must contain at least special character';
            return false;
        }

        return true;
    }

    /**
     * @param $password
     * @return bool
     */
    public function isMedium($password)
    {
        if (!$this-&gt;isNormal($password)) {
            return false;
        }

        if (!preg_match("#[a-z]#", $password)) {
            $this-&gt;message = '{field} must contain at least one lowercase letter';
            return false;
        }

        if (!preg_match("#[A-Z]#", $password)) {
            $this-&gt;message = '{field} must contain at least one uppercase letter';
            return false;
        }

        return true;
    }

    /**
     * @return mixed
     */
    public function message()
    {
        if ($this-&gt;message) {
            return $this-&gt;message;
        }

        return "{field} must be a good password";
    }
}
/**
 * @param $strength
 * @param $password
 * @return bool
 */
public function is($strength, $password)
{
    $method = sprintf("is%s", ucwords($strength));
    return call_user_func([$this, $method], $password);
}


This is not okay.

You're taking user input... (or something that I assume to be user input...) and then looking for a method in your own class, and then executing it. This whilst you know or at least can reasonably assume that you know which values the user input might contain.

So let's nuke it.

If we nuke it, then we need a new implementation here.

/**
 * @param $field
 * @param $password
 * @param Arguments $args
 * @return mixed
 */
public function validate($field, $password, Arguments $args)
{
    $type = $args-&gt;getVariables();

    if ($type &amp;&amp; $type != self::NORMAL) {
        return $this-&gt;is($type[ 0 ], $password);
    }

    return $this-&gt;isNormal($password);
}


Well, we can use a switch. See also the documentation here: http://php.net/manual/en/control-structures.switch.php (I'm not familiar with PHP syntax, but you should understand the gist of the idea.)

/**
 * @param $field
 * @param $password
 * @param Arguments $args
 * @return mixed
 */
public function validate($field, $password, Arguments $args)
{
    $type = $args-&gt;getVariables();

    if ($type &amp;&amp; $type != self::NORMAL) {
        switch ($type [ 0 ]) {
            case self::NORMAL:
                return $this-&gt;isNormal($password);
                break;
            case self::MEDIUM:
                return $this-&gt;isMedium($password);
                break;
            case self::STRONG:
                return $this-&gt;isStrong($password);
                break;
        }
    }

    return $this-&gt;isNormal($password);
}


Lastly, I'd say you should reorder your methods so they are ordered as "normal", "medium" and "strong" in the code as well. It reads better.