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

Php 类中的ANDING布尔表达式和单个if语句的意外输出,php,oop,single-responsibility-principle,Php,Oop,Single Responsibility Principle,我编写了一个从数组中获取数据的函数。该函数的一部分是验证数据,它检查键是否为空以及数组键是否不存在(编辑后的my bad)。函数如下所示: public function getData($key = "") { if (!empty($key) && !array_key_exists($key, $this->data)) { throw new ConfigurationException("$key does not exist");

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

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];
}
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];
}
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];
}
在应用SRP原则之后,通过将“验证”放入另一个类,它看起来是这样的:

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];
}
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];
}
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];
}
从这两个代码片段中,我期望得到相同的结果,因为我将
isPresent
函数之前的code>运算符,使其检查条件是否为false

为什么布尔表达式不一样,结果也不一样?

您写道“该函数中的一部分是数据验证,它检查键是否为空以及数组键是否存在”。因此,您应该执行以下操作:

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
之后的代码!这里,您缺少一个
清空()之前

结尾应该是这样的:

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];
}
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];
}
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];
}
阅读后,由于您混淆了布尔逻辑,您写道“该函数中的一部分是数据验证,它检查键是否为空以及数组键是否存在”,因此您应该执行以下操作:

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
之后的代码!这里,您缺少一个
清空()之前

结尾应该是这样的:

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];
}
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];
}
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];
}

请阅读,因为您混淆了布尔逻辑,。

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

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

!(true && false) --> !(false) --> true
然而,
!A&&!B
相当于
!(A | | B)


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

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

!(true && false) --> !(false) --> true
然而,
!A&&!B
相当于
!(A | | B)


这两行不一样:

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

    return empty($key) && array_key_exists($key, $data);
德摩根的:

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

由于您的
返回值
版本在调用点被否定,因此您正在有效地执行!P | | |!Q版本,与
中的
&&
不完全相同,如果
这两行不相同:

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

    return empty($key) && array_key_exists($key, $data);
德摩根的:

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

由于您的
返回值
版本在调用点被否定,因此您正在有效地执行!P | | |!Q版本,它与
中的
&&
不完全相同,如果
函数体
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()
方法中,将导致上面显示的代码。

函数体
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()
方法中会导致上面显示的代码。

如果您将此与实际问题关联,您可能会获得向上投票,而不是忽略或向下投票@RiggsFolly实际的问题是“为什么布尔表达式不一样,结果也不一样?”如果你把这个问题与实际问题联系起来,你可能会得到赞成票,而不是被忽略票或反对票@RiggsFolly实际的问题是“为什么布尔表达式不一样,结果也不一样?”参见De Morgan定律():
!(A&B)=(!A)| |(!B)
见德摩根定律():
!(A&&B)=(!A)|(!B)
@DownVoter--是否要评论?您更改了
getData()
函数的语义。它最初的目的是返回一个值(给定一个非空的有效键)或整个数据数组(当提供一个空字符串作为键时)。您的版本删除了后者。我刚刚注意到我自己的问题中有一个错误,我想说我还必须检查数组键是否也不符合预期。不过,我喜欢这种解释。@axiac我在开始回答时引用了一句与实现不匹配的话,这是我选择依赖的。因为OP显然把De Morgan搞糊涂了,所以解释源代码不是个好主意。我选择了他的描述。@DownVoter--要不要评论?您更改了
getData()
函数的语义。它最初的目的是返回一个值(给定一个非空的有效键)或整个数据数组(当提供一个空字符串作为键时)。您的版本删除了后者。我刚刚注意到我自己的问题中有一个错误,我想说我还必须检查数组键是否也不符合预期。不过,我喜欢这种解释。@axiac我在开始回答时引用了一句与实现不匹配的话,这是我选择依赖的。因为OP显然把De Morgan搞糊涂了,所以解释源代码不是个好主意。我选择了他的描述。