Which method is preferred strstr or strpos?
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.
johnlemon
Updated on May 29, 2020Comments
-
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 almost 13 yearsthat's a completely bogus explanation -
strstr()
returns everything before or after the needle, so it first has to do the equivalent ofstrpos()
and then create that substring. That's where the performance hit is. -
Alnitak almost 13 yearsIt 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 callstrstr()
. -
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 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 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 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 almost 13 yearsYou mean the function that returns the position that you do not need?
-
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 almost 13 yearsOh, there is one. But you will get even more upset when I mention
ereg
orpreg_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 almost 13 yearsnow 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 almost 13 yearsIt'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 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 whystrstr
should be "better" thanstrpos
.strpos
is clearly more appropriate for the job, already for the reason you mentioned. -
mario almost 13 years@nikic:
ereg
was the shorter example overpreg_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 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 whatstrpos
tells you. You will notice that in many other languages you find substrings similarly. One example that comes to mind is JavaScriptsindexOf
. -
NikiC almost 13 years@mario: Damned, I said I don't want to argue and now I started ... :(
-
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 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 over 10 yearsWhile this benchmark is usefull it does not measure memory consumption, also does not take into account long strings, like kbytes or mbytes.
-
Buttle Butkus about 10 yearsTo elaborate on fedmich's comment: I always use
if(strpos($haystack,$needle) !== false) { // do something }
, neverif(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 almost 10 yearsPeople 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 almost 9 years
strstr
is too similiar tostrtr
-
NiCk Newman over 8 yearsHuh? @user133408 Long strings and larger byte strings would even take longer.
-
E Ciotti almost 5 years
strstr
needs a strict comparison too Example:('123450', '0')
-
xpoback almost 2 years
(bool) strstr('Hell0 w0rld', $search);
will returnfalse
with$search = ' '
or$search = '0'
and this is already not was is expected.