多字段空验证的最佳实践


Best pratice for null verifications of multiple fields

在我的程序中有一个时刻,我到达了以下条件:

if ($Student->getClass() != null) {
    if ($Student>getClass()->isActive()) {
        if ($Student->getClass()->getAcceptedGrades() != null) {
            if (in_array($StudentGrade, $Student->getClass()->getAcceptedGrades())) { 
                echo "The student has a acceptable grade."
            }
        }
    }
}

我问自己是否没有更好的方法来做这种验证。

我不能尝试验证null对象中的值,所以我总是需要验证我是否拥有我正在访问的对象

只要你的方法返回null,你就会有这些检查。

您可以使用java.util的PHP端口。这是可选的,但这仍然需要你在任何地方检查。不过看起来好点了。

但是真正的问题是返回null。例如,你的

$Student->getClass()->getAcceptedGrades()  

显然返回nullarray。如果该方法总是返回一个空数组而不是null,您可以在调用in_array之前摆脱空检查。一般来说,一个方法只返回一个东西是很好的做法。这样可以避免在检查返回值时消耗代码。

如果您将getAcceptedGrades更改为始终返回数组,则剩下

if ($Student->getClass() != null) {
    if ($Student>getClass()->isActive()) {
        if (in_array($StudentGrade, $Student->getClass()->getAcceptedGrades())) { 
            echo "The student has an acceptable grade."
        }
    }
}

正如你所看到的,所有的if检查基本上都对getClass返回的内容进行操作。我假设它是一个Class/Course对象。它的缺点是,包含这些if检查的代码知道验证可接受等级的条件。相反,Course对象应该是这方面的专家,因为它包含了相关的信息。那么为什么不直接向Course对象添加一个方法hasAcceptableGrade()呢?

public function hasAcceptableGrade($StudentGrade)
{
    return $this->isActive()
        && in_array($StudentGrade, $this->getAcceptedGrades());
}

这样,具有if检查的代码不需要知道如何计算可接受的分数的细节。相反,它只询问Course对象,这将给您留下

if ($Student->getClass() != null) {
    if ($Student->getClass()->hasAcceptableGrade($StudentGrade) {
        echo "The student has an acceptable grade."
    }
}

要摆脱最后的null检查,您将再次确保始终返回Class/Course对象。如果这是不可能的,因为学生没有注册,要么让getClass引发StudentNotEnrolled异常,并将代码更改为

try {
    if ($Student->getClass()->hasAcceptableGrade($StudentGrade) {
        echo "The student has an acceptable grade."
    }
} catch (StudentNotEnrolledException $e) {
    echo "Student is not enrolled"
}

或在这种情况下引入Null对象,例如

class NullCourse
{
    public function hasAcceptableGrade($StudentGrade)
    {
        return false;
    }    
}

我们在这里总是返回false,因为我们假设没有课程的学生将永远不会获得可接受的课程成绩。如果你不想遵循这个逻辑,你可以明显地将其更改为始终为真,或者在这里提高StudentNotEnrolledException

如果返回值为false,这将使代码减少为

if ($Student->getClass()->hasAcceptableGrade($StudentGrade) {
    echo "The student has an acceptable grade."
}

现在唯一剩下的事情是将hasAccetableGrade方法移动到Student对象上,这样您的消费代码就可以简单地询问Student对象,而不是知道它首先需要获取Course对象。我省略了示例代码。你将以

结尾
if ($Student->hasAcceptableGrade($StudentGrade) {
    echo "The student has an acceptable grade."
}

只有一个if。没有多个条件。

在student类中添加一个函数来完成此操作。

class Student {
    public function hasEmptyClass() {
        $class = $this->getClass();
        if (! $class instanceof Class || ! $class->hasAcceptableGrade(...)) {
            return true;
        }
        return false;
    }
}