我接管了一个更大的代码库,其中有几个警告和错误。
我不断遇到这样的说法:
foreach( $object->keys => $key ){
...
}
在错误日志中,我可以看到$object
为null。
最简单的方法是什么,来检查上面的书面陈述不会破裂?
为了100%确定,我会做这样的事情:
if( isset( $object ) && is_array( $object->keys ) ){
foreach( $object->keys => $key ){
...
}
}
但是可读性明显下降。
我还可以制作一个助手函数,这样就可以了:
if( myHelper::canBeForeached( $object, 'keys' ) ){ // naming would obviously be changed
foreach( $object->keys => $key ){
...
}
}
但这似乎也很糟糕。
实现这一点,同时保持代码可读性的最简单/最漂亮的方法是什么?
有很多方法可以实现这一点。这是最短的方法。
如果使用??
null合并运算符作为默认值,则在未定义$object
或->keys
的情况下,将传递[]
或空数组进行迭代,显然不会发生任何事情。这是避免将foreach
循环封装在条件中的一种方法。
foreach($object->keys ?? [] as $key) {
// If $object or ->keys is undefined, nothing happens.
}
现在,有些人可能会反对这是不清楚或无法读取;但至少它不是一个样板,而且添加起来很快。这种方法假设如果$object
存在并且具有属性keys
,那么keys
将是可迭代的。否则,将导致上的警告。必须是array|object类型。
除此之外,如果您想确保它是一个对象,则必须使用条件检查isset($object)
或gettype($object) === 'object'
来包装所有循环。由于某种原因,is_object()
将对未定义的变量发出警告。同样,如果变量未定义,则is_null()
返回true
,在取反时基本上表现为!isset()
。
如上所述,如果您的遗留代码具有多个命名属性的对象,这些属性不可迭代,但也不为null(例如->keys = 'duck'
(,则在$object->keys
进入循环尝试迭代之前,您必须使用is_iterable()
对其进行检查。
如果将未定义的对象传递到is_iterable
中,则再次发出警告。然而,您可以再次使用null合并的功能,其中,如果$object
或->keys
未定义,则下面的检查读取为is_iterable(false)
(或要评估的任何其他不可迭代值(:
if(is_iterable($object->keys ?? false)) {
foreach($object->keys as $key) {
//...
}
}
这可能是包裹你的循环的唯一条件。
附言:关于OP中可能的解决方案:如果与未定义的变量一起使用,辅助函数会导致警告。此外,如果定义了object
但没有->keys
属性,则if( isset( $object ) && is_array( $object->keys ) )
将导致警告。