Vitalie Ciubotaru Vitalie Ciubotaru - 5 months ago 8
PHP Question

isset and != in the same if clause

In my script a particular array element (say,

$foo['bar']
) can take different values, or no value at all. A particular action is triggered if the value of
$foo['bar']
is not equal to, say, 42. The following code

if (!isset($foo['bar']) || ($foo['bar'] != '42')) action()


is not ideal, because php issues a warning about when
$foo['bar']
is not set.

Question: is there an elegant way to test for such condition?

Answer

This code:

if (!isset($foo['bar']) || $foo['bar'] != 42) {
}

Because of short-circuiting logic will actually not issue any warnings, because it skips at the first truthy condition, in this case that happens if $foo['bar'] is not defined.

This can also be seen from the opcodes that the compiler generates for your code:

compiled vars:  !0 = $foo
line  # *  op                           fetch          ext  return  operands
------------------------------------------------------------------------------
   3  0  >   ZEND_ISSET_ISEMPTY_DIM_OBJ                    1  ~0      !0, 'bar'
      1      BOOL_NOT                                         ~1      ~0
      2    > JMPNZ_EX                                         ~1      ~1, ->6
      3  >   FETCH_DIM_R                                      $2      !0, 'bar'
      4      IS_NOT_EQUAL                                     ~3      $2, 42
      5      BOOL                                             ~1      ~3
      6  > > JMPZ                                                     ~1, ->8
   4  7  > > JMP                                                      ->8
      8  > > RETURN                                                   1

The below opcode is important:

2    > JMPNZ_EX                                         ~1      ~1, ->6

The inverted outcome of isset($foo['bar']) gets checked and if truthy the code jumps over the next few statements that actually inspect the value of $foo['bar'], thereby avoiding any notices.

This also means that if you would reverse the two operands of || you will get a notice and the second operand is mostly useless anyway.

Because values like 0, false, [], etc. are also not equal to 42 you can use empty() as well:

if (empty($foo['bar']) || $foo['bar'] != 42) {
}

This arguably makes the code easier to read.