strpos() and Argument Order in PHP

(2016)

One of the great puzzles in the modern era is the apparent inconsistency of PHP's function signatures.

For me, it's strpos() that takes the cake.

strpos($haystack, $needle);

A frequent use case for strpos() is answering the question "is a particular substring present in a string?"

Conceptually, this is similar to in_array(), which answers the question "is a particular element present in an array?"

However, in_array() has the opposite signature:

in_array($needle, $haystack)

It's probably just personal preference, but something about the strpos() signature is less intuitive to me. I must've looked up that function 100+ times in my career and I'm certain that http://php.net/manual/en/function.strpos.php is one of the most visited pages on the internet. Thankfully modern IDEs have intellisense, but I still have to stop and think about it every single time.

So is there some underlying logic here?

Grepping through the documentation, we find the following:

In the haystack-needle camp, we have the string functions:

iconv_strpos ($haystack, $needle, $offset = 0, $charset = 'ini_get("iconv.internal_encoding")
iconv_strrpos ($haystack, $needle, $charset = 'ini_get("iconv.internal_encoding")
grapheme_strpos($haystack, $needle, $offset = 0)
grapheme_stripos($haystack, $needle, $offset = 0)
grapheme_strrpos($haystack, $needle, $offset = 0)
grapheme_strripos($haystack, $needle, $offset = 0)
grapheme_strstr($haystack, $needle, $before_needle = false)
grapheme_stristr($haystack, $needle, $before_needle = false)
grapheme_extract($haystack, $size, $extract_type = null, $start = 0, &$next = null)
strpos ($haystack, $needle, $offset = 0)
stripos ($haystack, $needle, $offset = null)
strrpos ($haystack, $needle, $offset = 0)
strripos ($haystack, $needle, $offset = null)
strstr ($haystack, $needle, $before_needle = null)
stristr ($haystack, $needle, $before_needle = null)
strrchr ($haystack, $needle)
strpbrk ($haystack, $char_list)
substr_count ($haystack, $needle, $offset = null, $length = null)
strchr ($haystack, $needle, $part)
mb_strpos ($haystack, $needle, $offset = 0, $encoding = null)
mb_strrpos ($haystack, $needle, $offset = 0, $encoding = null)
mb_stripos ($haystack, $needle, $offset = 0, $encoding = null)
mb_strripos ($haystack, $needle, $offset = 0, $encoding = null)
mb_strstr ($haystack, $needle, $part = null, $encoding = null)
mb_strrchr ($haystack, $needle, $part = null, $encoding = null)
mb_stristr ($haystack, $needle, $part = null, $encoding = null)
mb_strrichr ($haystack, $needle, $part = null, $encoding = null)
mb_substr_count ($haystack, $needle, $encoding = null)

And in the needle-haystack camp, we have the array functions:

in_array ($needle, array $haystack, $strict = false)
array_search ($needle, array $haystack, $strict = null)

Perhaps it's not TOTALLY crazy afterall.

But that still doesn't make it easy to remember which is which.