class 和单个 if 语句中的 ANDING 布尔表达式的意外输出

Unexpected output on a ANDING boolean expression in a class and a single if statement

我写了一个从数组中获取数据的函数。该功能的一部分是数据验证,它检查键是否为空以及数组键是否不存在(编辑后我的错误)。该函数如下所示:

public function getData($key = "")
{
    if (!empty($key) && !array_key_exists($key, $this->data)) {
        throw new ConfigurationException("$key does not exist");
    }
    return empty($key) ? $this->data : $this->data[$key];
}

应用 SRP 原理后,通过将 'verification' 放入另一个 class,它看起来像这样:

class ConfigurationVerificationHandler
{

    public function isPresent($key, array $data)
    {
        return empty($key) && array_key_exists($key, $data);
    }
}

public function getData($key = "")
{
    $verificationHandler = new ConfigurationVerificationHandler();
    if (!$verificationHandler->isPresent($key, $this->data)) {
        throw new ConfigurationException("$key does not exist");
    }
    return empty($key) ? $this->data : $this->data[$key];
}

从这两个片段中,我期望得到相同的结果,因为我将 ! 运算符放在 isPresent 函数之前,使其检查条件是否为假。

布尔表达式不一样,结果不一样,这是怎么回事?

你写了"A part in that function is verification of the data, it checks if the key is NOT empty and if the array key exists.",所以你应该这样做:

public function getData($key = "")
{
    // Throw exception if key is empty OR array-key does not exist
    if (empty($key) || !array_key_exists($key, $this->data)) {
        throw new ConfigurationException("$key does not exist");
    }
    // This won't be executed if $key is empty or does not exist
    return $this->data[$key];
}

请注意,由于您没有捕获异常,throw 之后的代码将不会执行!在这里,您在 empty().

之前缺少一个 !
public function isPresent($key, array $data)
{
    return !empty($key) && array_key_exists($key, $data);
}

结尾应该是这样的:

public function getData($key = "")
{
    $verificationHandler = new ConfigurationVerificationHandler();
    if (!$verificationHandler->isPresent($key, $this->data)) {
        throw new ConfigurationException("$key does not exist");
    }
    // $key can't be empty here
    return $this->data[$key];
}

阅读PHP Exception handling and since you're confusing boolean logig, De Morgan's laws

!A && !B!(A && B) 不同。只需要查看一个变量为真(让我们选择 A)而另一个为假的情况:

!true && !false --> false && true --> false

!(true && false) --> !(false) --> true

然而,!A && !B等同于!(A || B)

!(true || false) --> !(true) --> false

这两行不一样:

if (!empty($key) && !array_key_exists($key, $this->data)) {

    return empty($key) && array_key_exists($key, $data);

德摩根的:

 !(P && Q) -> (!P) || (!Q)

由于您的 return 版本在调用点被否定,您实际上是在执行 !P || !Q 版本,与 if.

中的 && 不太一样

函数体 isPresent() 应该是:

public function isPresent($key, array $data)
{
    return empty($key) || array_key_exists($key, $data);
}

您开始于:

if (! empty($key) && ! array_key_exists($key, $this->data)) {

这相当于:

if (! (empty($key) || array_key_exists($key, $this->data))) {

下一步,将条件移动到 isPresent() 方法中会导致上面公开的代码。