Which method is preferred strstr or strpos?

52,969

Solution 1

From the PHP online manual:

If you only want to determine if a particular needle occurs within haystack, use the faster and less memory intensive function strpos() instead.

Solution 2

Here are some other answers (+benchmarks) I got to my question, which is almost the same (I didn't realize yours when asking).


In the meantime I also made my own benchmark test, which I ran 1000000 times for each relevant functions (strstr(), strpos(), stristr() and stripos()).
Here's the code:

<?php

function getmicrotime() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float) $usec + (float) $sec);
}

$mystring = 'blahblahblah';  
$findme = 'bla';  

echo 'strstr & strpos TEST:<pre>';
$time_start = getmicrotime();
for($i=0; $i<1000000; $i++) strstr($mystring, $findme);
$time_needed_strstr = getmicrotime() - $time_start;
echo 'strstr():            ',
    round( $time_needed_strstr , 8 ). PHP_EOL;

$time_start = getmicrotime();
for($i=0; $i<1000000; $i++) stristr($mystring, $findme);
$time_needed_stristr = getmicrotime() - $time_start;
echo 'stristr():           ',
    round( $time_needed_stristr , 8 ) . PHP_EOL;

$time_start = getmicrotime();
for($i=0; $i<1000000; $i++) strpos($mystring, $findme) !== false;
$time_needed_strpos = getmicrotime() - $time_start;
echo 'strpos() !== false:  ',
    round( $time_needed_strpos , 8 ) . PHP_EOL;

$time_start = getmicrotime();
for($i=0; $i<1000000; $i++) stripos($mystring, $findme) !== false;
$time_needed_stripos = getmicrotime() - $time_start;
echo 'stripos() !== false: ',
    round( $time_needed_stripos , 8 ) . PHP_EOL;

echo PHP_EOL;

echo 'time_needed_stristr - time_needed_strstr: ',
     round( $time_needed_stristr - $time_needed_strstr , 8) . PHP_EOL;
echo 'time_needed_stripos - time_needed_strpos: ',
     round( $time_needed_stripos - $time_needed_strpos , 8) . PHP_EOL;

echo PHP_EOL;

echo 'time_needed_strstr  - time_needed_strpos:  ',
     round( $time_needed_strstr - $time_needed_strpos , 8) . PHP_EOL;
echo 'time_needed_stristr - time_needed_stripos: ',
     round( $time_needed_stristr - $time_needed_stripos , 8) . PHP_EOL;

echo '</pre>';

?>

And here is the first output, which shows that strpos() is the winner:

strstr & strpos TEST:
strstr():            2.39144707
stristr():           3.65685797
strpos() !== false:  2.39055395
stripos() !== false: 3.54681897

time_needed_stristr - time_needed_strstr: 1.2654109
time_needed_stripos - time_needed_strpos: 1.15626502

time_needed_strstr  - time_needed_strpos:  0.00089312
time_needed_stristr - time_needed_stripos: 0.110039 

The next one is similar to the first output (strpos() is the winner again):

strstr & strpos TEST:
strstr():            2.39969015
stristr():           3.60772395
strpos() !== false:  2.38610101
stripos() !== false: 3.34951186

time_needed_stristr - time_needed_strstr: 1.2080338
time_needed_stripos - time_needed_strpos: 0.96341085

time_needed_strstr  - time_needed_strpos:  0.01358914
time_needed_stristr - time_needed_stripos: 0.25821209

Below is another one, which is more interesting, because in this case, strstr() is the winner:

strstr & strpos TEST:
strstr():            2.35499191
stristr():           3.60589004
strpos() !== false:  2.37646604
stripos() !== false: 3.51773095

time_needed_stristr - time_needed_strstr: 1.25089812
time_needed_stripos - time_needed_strpos: 1.14126492

time_needed_strstr  - time_needed_strpos:  -0.02147412
time_needed_stristr - time_needed_stripos: 0.08815908

This means it can really depend on "environmental circumstances", which are sometimes hard to influence, and can change the result of "micro optimization tasks" like this, in case you are just checking whether a string exists in another one or not.

BUT I think in most cases, strpos() is the winner in comparison to strstr().

I hope this test was useful for someone.

Solution 3

Many developers use strpos for micro optimization purposes.

Using strstr also only works if the resulting string cannot be interpreted as false in boolean context.

Overcome by events: PHP8 introduced str_contains, the "right tool for the job" (with shims available for older setups). Which does exactly what everyone has been glamoring for, but without the interpreter-level comparison and syntactic overhead.

Share:
52,969
johnlemon
Author by

johnlemon

Updated on May 29, 2020

Comments

  • johnlemon
    johnlemon almost 4 years

    I noticed a lot of developers are using both strstr and strpos to check for a substring existence. Is one of them preferred and why ?

  • Alnitak
    Alnitak almost 13 years
    that's a completely bogus explanation - strstr() returns everything before or after the needle, so it first has to do the equivalent of strpos() and then create that substring. That's where the performance hit is.
  • Alnitak
    Alnitak almost 13 years
    It is not micro optimisation, it's called using the right function for the job. If I want the string's position, I call strpos(). If I wanted the substring after that position, I call strstr().
  • mario
    mario almost 13 years
    @Alnitak: What I was saying. If you want to check for the presence of a string, then there's a function for that. If you actually do need the position, then there's another. -- When you probe for the position without actually needing the position, then that's hardly "using the right function for the job". The intention is clearly to optimize micro seconds away. (Isn't that what you cited?)
  • Alnitak
    Alnitak almost 13 years
    @mario but there is no function whose only purpose is checking whether a substring exists. The position of the substring (if found) is free information once you've actually found it. OTOH, strstr does more than is required, which is why it's slower.
  • mario
    mario almost 13 years
    @Alnitak: Mind you, not news. You seem very adamant about pointing out the performance difference, and only that. That's a tell tale sign of micro optimization. It doesn't make a blip in the profiler. Where it does make a difference is in code readability.
  • Alnitak
    Alnitak almost 13 years
    @mario actually I would care only very slightly about the performance. I do care very much about using the right function for the job ;-)
  • mario
    mario almost 13 years
    You mean the function that returns the position that you do not need?
  • Alnitak
    Alnitak almost 13 years
    @mario like I said, that's free information - you cannot prove existence without incidentally calculating position. There isn't a PHP function that only tests for existence.
  • mario
    mario almost 13 years
    Oh, there is one. But you will get even more upset when I mention ereg or preg_match - because they are measurably slower. (Notice the "measurably". You have been complaining only because I pointed out that using strpos is a "micro optimization".)
  • Alnitak
    Alnitak almost 13 years
    now you're being silly. preg_match's job isn't searching for a string within a string, it's matching a string against a regexp.
  • mario
    mario almost 13 years
    It's not forbidden to use a fixed string as regex. I have no idea about the system implementation of ereg("test",$str), but I doubt the search algorithm itself could be slower than PHPs naive binary string search. (To bring the discussion back to your primary concern.)
  • NikiC
    NikiC almost 13 years
    @mario: And let us all use ereg, iei! Really, regular expressions are my most favorite tool PHP offers, but a) ereg is deprecated and b) Using a regex to match against a string is 1. overkill and 2. often involves much more code, because you need to deal with escaping and 3. you may easily forget 2. I don't really see your point why strstr should be "better" than strpos. strpos is clearly more appropriate for the job, already for the reason you mentioned.
  • mario
    mario almost 13 years
    @nikic: ereg was the shorter example over preg_match regarding a "PHP function that only tests for existence". It's not useful for the case at hand. Obviously. -- Nevertheless, the OP wasn't about the "fastest" function, but about the "preferred". strpos falls flat without the supporting !== strong boolean check. strstr is more convenient in other settings and when you can overlook the minuscle speed difference. (e.g. as simpler callback in an array_map construct)
  • NikiC
    NikiC almost 13 years
    @mario: Really, I don't want to argue about that. It's probably a quite philosophical question. I use strpos because I regard it the "right function for the job" as you called it. Reasoning is simple: If a string is a substring of another string, it must occur at some position in this string. And this is what strpos tells you. You will notice that in many other languages you find substrings similarly. One example that comes to mind is JavaScripts indexOf.
  • NikiC
    NikiC almost 13 years
    @mario: Damned, I said I don't want to argue and now I started ... :(
  • mario
    mario almost 13 years
    @nikic: Actually I also just use strpos. Here I'm just trying to pretend I knew better and used the more readable syntax most of the time. -- The language comparison is an interesting point. Python for example has .find and .index. And the latter has no ambigious results, but gives an exception. (which otoh is a bit overkill)
  • fedmich
    fedmich over 11 years
    +1, You may use strpos or stripos. and don't forget to check the warnings on the php doc about using === FALSE;
  • Admin
    Admin over 10 years
    While this benchmark is usefull it does not measure memory consumption, also does not take into account long strings, like kbytes or mbytes.
  • Buttle Butkus
    Buttle Butkus about 10 years
    To elaborate on fedmich's comment: I always use if(strpos($haystack,$needle) !== false) { // do something }, never if(strpos($haystack,$needle)) { // do bad things }. strpos will return 0 if the $needle is at the very beginning of $haystack, and 0 is considered equal to false. (0 == false) evaluates to true. (0 === false) evaluates to false.
  • Déjà vu
    Déjà vu almost 10 years
    People coming from C may think about using the strchr function, but in PHP it's actually an alias for strstr, so strpos is a better choice.
  • Mārtiņš Briedis
    Mārtiņš Briedis almost 9 years
    strstr is too similiar to strtr
  • NiCk Newman
    NiCk Newman over 8 years
    Huh? @user133408 Long strings and larger byte strings would even take longer.
  • E Ciotti
    E Ciotti almost 5 years
    strstr needs a strict comparison too Example: ('123450', '0')
  • xpoback
    xpoback almost 2 years
    (bool) strstr('Hell0 w0rld', $search); will return false with $search = ' ' or $search = '0' and this is already not was is expected.