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 ?
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.
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. –
Np 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.
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.
strpos()
. If I wanted the substring after that position, I call strstr()
. –
Phonetic strstr
does more than is required, which is why it's slower. –
Phonetic 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".) –
Ultramundane preg_match's
job isn't searching for a string within a string, it's matching a string against a regexp. –
Phonetic 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.) –
Ultramundane 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. –
Doby 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) –
Ultramundane 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
. –
Doby 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) –
Ultramundane (bool) strstr('Hell0 w0rld', $search);
will return false
with $search = ' '
or $search = '0'
and this is already not was is expected. –
Squamulose strpos()
detects where in the haystack a particular needle lies.
strstr()
tests whether the needle is anywhere in the haystack.
Therefore strpos()
is faster and less memory consuming.
A reason for strstr()
: if your needle is at the beginning of a string, strpos()
returns 0
(so you have to check it with === false
)
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. –
Phonetic I prefer strstr()
for readability and easy coding.. strpos() !==false
is confusing a bit..
strstr
is too similiar to strtr
–
Clap strstr
needs a strict comparison too Example: ('123450', '0')
–
Steffi © 2022 - 2024 — McMap. All rights reserved.