use*_*303 3 php arrays if-statement
我有一个类似这样的代码,我只是想知道在单个 if 语句中使用大量“and”“or”是否是个好习惯
if (array_key_exists(self::SUB_FORM_CONTACT, $data) &&
array_key_exists('company', $data[self::SUB_FORM_CONTACT]) &&
((array_key_exists('salesRegion', $data[self::SUB_FORM_CONTACT]['company']) && !empty($data[self::SUB_FORM_CONTACT]['company']['salesRegion'])) ||
(array_key_exists('serviceRegion', $data[self::SUB_FORM_CONTACT]['company']) && !empty($data[self::SUB_FORM_CONTACT]['company'][''])))
) {
}
Run Code Online (Sandbox Code Playgroud)
或者有没有更好的方法来做到这一点?
建议避免复杂的条件表达式,因为它们难以阅读和理解。但是,如果表达式仅使用一种类型的逻辑运算符来连接条件,则可以很容易理解。
例如:
if ($a && $b || $c && ! $d) {
echo("Yes!");
}
Run Code Online (Sandbox Code Playgroud)
你能一眼看出if
分支( echo()
)中的代码什么时候执行吗?很可能不会。该表达式包含所有逻辑运算的混合,如果不绘制$a
、$b
、$c
和的所有可能值的表,则很难评估其最终值$d
。
另一方面,表达式:
if ($a && $b && $c && $d) {
echo("Hooray!");
}
Run Code Online (Sandbox Code Playgroud)
更容易掌握。当、 、和全部同时出现时,
该语句执行。echo()
$a
$b
$c
$d
TRUE
就您而言,情况比上面介绍的第一个情况更复杂。它包含所有逻辑运算符和括号,并且子表达式相当长。
为了保持其可读性,我会将复杂的条件提取到返回布尔值(谓词)的(私有或受保护)方法中。
private function isValidData(array $data)
{
if (array_key_exists(self::SUB_FORM_CONTACT, $data) &&
array_key_exists('company', $data[self::SUB_FORM_CONTACT]) &&
((array_key_exists('salesRegion', $data[self::SUB_FORM_CONTACT]['company']) && !empty($data[self::SUB_FORM_CONTACT]['company']['salesRegion'])) ||
(array_key_exists('serviceRegion', $data[self::SUB_FORM_CONTACT]['company']) && !empty($data[self::SUB_FORM_CONTACT]['company'][''])))
) {
return TRUE;
} else {
return FALSE;
}
}
Run Code Online (Sandbox Code Playgroud)
并替换语句中的表达式if
:
if ($this->isValidData($data)) {
}
Run Code Online (Sandbox Code Playgroud)
在接下来的步骤中,我会将复杂的条件表达式拆分为较小的条件,逐一测试它们,并在可能的情况下使函数尽早isValidData()
返回 ( FALSE
)。
由于表达复杂且片段相对较长,因此很难按原样使用它。这就是为什么,在第一步中,我将条件提取到具有较短名称的局部变量中($a
,$b
如上):
private function isValidData(array $data)
{
$a = array_key_exists(self::SUB_FORM_CONTACT, $data);
$b = array_key_exists('company', $data[self::SUB_FORM_CONTACT]);
$c = array_key_exists('salesRegion', $data[self::SUB_FORM_CONTACT]['company']);
$d = empty($data[self::SUB_FORM_CONTACT]['company']['salesRegion']);
$e = array_key_exists('serviceRegion', $data[self::SUB_FORM_CONTACT]['company']);
$f = empty($data[self::SUB_FORM_CONTACT]['company']['']);
// this should probably read 'serviceRegion' -------^
if ($a && $b && (($c && ! $d) || ($e && ! $f))) {
return TRUE;
} else {
return FALSE;
}
}
Run Code Online (Sandbox Code Playgroud)
现在一切看起来都很清楚了,我们甚至发现了一个错误。伟大的!
让我们尝试理清这个(现在更容易阅读)条件:
if ($a && $b && (($c && ! $d) || ($e && ! $f))) {
return TRUE;
} else {
return FALSE;
}
Run Code Online (Sandbox Code Playgroud)
如果我们一次进行一个测试并在结果明显后立即返回(TRUE
或),可能会变得更容易理解。当和以及包含表达式其余部分的括号同时出现时,FALSE
该函数返回。TRUE
$a
$b
TRUE
该if
语句可以这样重写:
if ($a) {
if ($b) {
if (($c && ! $d) || ($e && ! $f))) {
return TRUE;
}
}
}
return FALSE;
Run Code Online (Sandbox Code Playgroud)
通过反转 和 的条件$a
,$b
我们可以FALSE
提前返回:
if (! $a) {
return FALSE;
}
if (! $b) {
return FALSE;
}
if (($c && ! $d) || ($e && ! $f))) {
return TRUE;
}
return FALSE;
Run Code Online (Sandbox Code Playgroud)
代码现在看起来像这样:
private function isValidData(array $data)
{
$a = array_key_exists(self::SUB_FORM_CONTACT, $data);
$form = $data[self::SUB_FORM_CONTACT];
$b = array_key_exists('company', $form);
$c = array_key_exists('salesRegion', $form['company']);
$d = empty($form['company']['salesRegion']);
$e = array_key_exists('serviceRegion', $form['company']);
$f = empty($form['company']['serviceRegion']);
if (! $a) {
return FALSE;
}
if (! $b) {
return FALSE;
}
if (($c && ! $d) || ($e && ! $f))) {
return TRUE;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,因为从第二个开始的所有赋值都包含公共子表达式,所以$data[self::SUB_FORM_CONTACT]
我们已将其提取到局部变量中。同样的情况也适用于最后 4 个赋值(提取公共子表达式$form['company']
:
// ...
$b = array_key_exists('company', $form);
$company = $form['company'];
$c = array_key_exists('salesRegion', $company);
$d = empty($company['salesRegion']);
$e = array_key_exists('serviceRegion', $company);
$f = empty($company['serviceRegion']);
Run Code Online (Sandbox Code Playgroud)
让我们注意表达式中的内容$c && ! $d
:
array_key_exists('salesRegion', $company) && ! empty($company['salesRegion'])
Run Code Online (Sandbox Code Playgroud)
调用 toarray_key_exists()
并不是真正需要的。我猜它的目的是避免在$company['salesRegion']
访问且不$company
包含密钥时触发通知'salesRegion'
。当数组中不存在该键并且不会触发通知时,PHPempty()
构造将愉快地返回。TRUE
同样的情况也发生在$e && ! $f
. 这使我们能够完全删除$c
和$e
。现在的情况是这样的:
if (! $d || ! $f) {
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
或者
if (! ($d && $f)) {
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
通过否定条件:
if ($d && $f) {
return FALSE;
} else {
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
完整的函数现在如下所示:
private function isValidData(array $data)
{
$a = array_key_exists(self::SUB_FORM_CONTACT, $data);
$form = $data[self::SUB_FORM_CONTACT];
$b = array_key_exists('company', $form);
$company = $form['company'];
$d = empty($company['salesRegion']);
$f = empty($company['serviceRegion']);
if (! $a) {
return FALSE;
}
if (! $b) {
return FALSE;
}
if ($d && $f) {
return FALSE;
} else {
return TRUE;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以消除局部变量$a
、和$b
,并在知道它们不是之后移动和的初始化(每个变量都在对 的相应调用之后):$d
$f
$form
$company
NULL
array_key_exists()
该函数的最终形式是这样的:
/**
* Verify if the provided data is valid.
*
* @param array $data the data to validate
* @return boolean TRUE if the data is valid, FALSE if some field is missing or empty
*/
private function isValidData(array $data)
{
// $data must contain the contact form information
if (! (array_key_exists(self::SUB_FORM_CONTACT, $data))) {
return FALSE;
}
// The contact form information exists in $data
$form = $data[self::SUB_FORM_CONTACT];
// The form must contain company information
if (! (array_key_exists('company', $form))) {
return FALSE;
}
// The company information exists in the contact form
$company = $form['company'];
// The company must contains information about salesRegion or serviceRegion or both
if (empty($company['salesRegion']) && empty($company['serviceRegion'])) {
return FALSE;
}
// The data is valid
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
该代码比以前长了几行,但是:
if ($this->isValidData($data))
一眼就能明白那里发生了什么,而无需阅读和理解它是如何发生的;如果它有效,那就不用担心;