PHP -验证函数返回true|false,如果为false则返回消息


PHP - Validation function to return true|false, AND a message if false

我有一个返回truefalse的验证函数。
然而,我希望它提供的信息,什么问题是,当有一个。

假设函数是这样的:

function is_valid($val) {
  $result = true;
  if( rule_1_not_met ) $result = false;
  if( rule_2_not_met ) $result = false;
  return $result;
}

像这样使用

$val = $_GET['some_param'];
if(!is_valid($val)) $out .= 'Not so helpful feedback.';
...

我想我可以这样修改:

function is_valid($val) {
  $result = array(true, array());
  if( rule_1_not_met ) $result[1][] = 'Reason 1';
  if( rule_2_not_met ) $result[1][] = 'Reason 2';
  if(count($result[1]) > 0) $result[0] = false;
  return $result;
}

并像这样使用:

$val = $_GET['some_param'];
$validation_result = is_valid($val);
if(!$validation_result[0]) $out .= implode('<br/>', $validation_result[1]);
...

我的问题是

  • 我在吗,为了意想不到的结果?
  • 是否有更好的方法来实现这一点?

注:会让这个社区变成wiki

你的思路是对的,但我想用这种方式来做

function is_valid($val,&$mes) {
  $result = true;
  if( rule_1_not_met ) { $mes[]='message one'; $result = false; }
  if( rule_2_not_met ) { $mes[]='Message two'; $result = false; }
  return $result;
}
$mes=array();
if(isvalid($val,$mes) ===false)  $out .= implode('<br/>', $mes);

在我看来,你提出的解决方案很好。唯一的问题是,您必须记住$validation_result[0]是状态,$validation_result[1]包含消息。这对您来说可能没问题,但如果其他人使用您的代码,则很难维护。您可以做的一件事是,当您调用函数时,您可以使用数组解构至少存储具有有意义的变量名的结果。例如:

[$valid, $errors] = is_valid($val);
if(!$valid) $out .= implode('<br/>', $errors);

由于上面提到的原因,我喜欢Brad Thomas的解决方案,即创建一个包含消息和状态的专门类。由于属性已命名,因此您不必猜测如何访问验证信息。而且,当您尝试访问它们的属性时,大多数好的ide都会自动完成。

我也有一个替代的解决方案。而不是包含一个布尔值true或false。只返回消息数组。调用者只需要检查返回的数组是否有非零的错误数。下面是一个例子:

function get_errors($val) {
    $errors = array();
    if( rule_1_not_met ) $errors[] = 'Reason 1';
    if( rule_2_not_met ) $errors[] = 'Reason 2';
    return $errors;
}

那么调用者会这样使用它:

$val = $_GET['some_param'];
$validation_result = get_errors($val);
if (count($validation_result) > 0) $out .= implode('<br/>', $validation_result);

可以使用Result对象封装返回数据、消息和状态。

class Result( $bResult, $sMessage, $mData ) {
    public function __construct() {
        $this->bResult = $bResult;
        $this->sMessage = $sMessage;
        $this->mData = $mData;
    }
}

在你的代码中:

$result = new Result(true, 'some helpful message here', null);
$reasons = array();
function is_valid($val)
{
    global $reasons;
    if ( rule_1_not_met ) $reasons[] = 'Reason 1';
    if ( rule_2_not_met ) $reasons[] = 'Reason 2';
    if ( count($reasons) == 0 )
        return TRUE;
    else
        return FALSE;
}
if (!is_valid($condition))
{
    echo 'Was not valid for these reasons<br />';
    foreach($reasons as $reason)
        echo $reason, '<br>';
}
else
    echo 'Is valid!';

这个问题很老了,它展示了坏的和过时的做法。使用global是不被允许的,在这种情况下使用引用也是一样的。

只有凯夫·约翰逊的回答是直接的,但用法仍然可能令人困惑。一个更好的解决方案是写一个类,但不要像Brad Thomas的答案那样愚蠢。

class NumberValidator
{
    protected $errors;
    public function validate($number)
    {
        if(!is_numeric($number))
        {
            $this->errors[] = "The value provided is not numeric";
            return false;
        }
        if($number < 10)
        {
            $this->errors[] = "The number is less than 10";
            return false;
        }
        return true;
    }
    public function getErrors()
    {
        return $this->errors;
    }
} 

然后可以这样使用

$validator = new NumberValidator();
if($validator->validate($number)) {
    /*success*/ 
}

$validator->getErrors()可以用在其他地方