isset の存在理由

なんでこんな働きが似通った関数が複数存在しているんですか?

まぁ、もともと isset と array_key_exists は別のものですから。
本来、isset は「変数がセットされているかどうか調べる」ためのものであって、連想配列*1のキーが存在するかどうか調べるためのものではないはず。多分、今でいう register_globals = On の時代に*2

 <type type="checkbox" name="check" value="0"/>

チェックボックスに対して、

if (isset($check)) {
}

なんてやったりすることを想定していたんだろう。
あと、何気に isset は関数じゃなくて言語構造だったりする。なので、

$a = array('foo' => 1, 'bar' => NULL);
call_user_func_array('array_key_exists', array('foo', $a));

は OK で、

$a = array('foo' => 1, 'bar' => NULL);
call_user_func('isset', $a['foo']);

は NG。多分、速度の差もこの辺からだろう。で、isset の方が速いという情報とタイプ量から isset を連想配列のキーチェックに使うというイディオムが普及したんじゃないかと予想してみる。
あと似たようなのに、echo と print があって、これは両方とも言語構造だけど、echo が値を返さないのに print は値を返すから式の中で使える。で、その代わり echo はちょっと速いらしい。詳しいことはマニュアルからもリンクされているFAQTs - Knowledge Base - View Entry - What is the difference between echo and print?にあるけど、正直2つもいらないと思う。

*1:PHPは配列と連想配列の区別がない

*2:今もそういう環境あるけど