多分たまたまC言語実装がそうなっているだけなのでしょうが、タイトル通りの現象が起きます。起きるのは次の通りArrayAccessを実装した際のemptyです。
ArrayAccessの説明には次の様にあります。
ArrayAccess::offsetGet
(PHP 5, PHP 7)
ArrayAccess::offsetGet — オフセットを取得する
ArrayAccess::offsetExists
(PHP 5, PHP 7)
ArrayAccess::offsetExists — オフセットが存在するかどうか
説明 ¶
オフセットが存在するかどうかを返します。
このメソッドが実行されるのは、ArrayAccess
を実装したオブジェクト上で isset() あるいは
empty() を使用した場合です。注意:
empty() を使用すると ArrayAccess::offsetGet()
がコールされ、ArrayAccess::offsetExists() が
TRUE
を返すかどうかで空かどうかを判断します。
要するにemptyの真偽をArrayAccess::offsetExists && ArrayAccess::offsetGetという式で判断しています。このため最初の画像の様にArrayAccess::offsetExistsとArrayAccess::offsetGetにvar_dumpを仕込むとemptyと一度組み込み関数を使っただけで2か所のvar_dumpが走りました。
ArrayAccess::offsetExists && ArrayAccess::offsetGetという表現から予想できるように短絡評価をしています。そもそもnullの場合はArrayAccess::offsetExistsのみを実行して終わりです。