Which method is preferred strstr or strpos ? [closed]
Asked Answered
O

5

89

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 ?

Olomouc answered 28/4, 2011 at 14:53 Comment(1)
the benchmark you mentioned is versus substr not strstrBlues
P
132

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.

Phonetic answered 28/4, 2011 at 14:55 Comment(4)
+1, You may use strpos or stripos. and don't forget to check the warnings on the php doc about using === FALSE;Waterman
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.Np
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.Depression
Starting from March 2024 the note has been edited and not PHP.net recommends str_contains() instead of strpos() there. str_contains() appeared in PHP 8.Wilhelm
H
43

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.

Hilleary answered 28/4, 2011 at 19:10 Comment(2)
While this benchmark is usefull it does not measure memory consumption, also does not take into account long strings, like kbytes or mbytes.Pubes
Huh? @Pubes Long strings and larger byte strings would even take longer.Thorlay
U
8

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.

Ultramundane answered 28/4, 2011 at 14:56 Comment(16)
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().Phonetic
@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?)Ultramundane
@Ultramundane 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.Phonetic
@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.Ultramundane
@Ultramundane actually I would care only very slightly about the performance. I do care very much about using the right function for the job ;-)Phonetic
You mean the function that returns the position that you do not need?Ultramundane
@Ultramundane 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.Phonetic
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".)Ultramundane
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.Phonetic
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.)Ultramundane
@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.Doby
@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)Ultramundane
@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.Doby
@mario: Damned, I said I don't want to argue and now I started ... :(Doby
@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)Ultramundane
(bool) strstr('Hell0 w0rld', $search); will return false with $search = ' ' or $search = '0' and this is already not was is expected.Squamulose
B
0

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)

Blues answered 28/4, 2011 at 14:56 Comment(1)
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.Phonetic
P
-2

I prefer strstr() for readability and easy coding.. strpos() !==false is confusing a bit..

Pula answered 19/12, 2014 at 16:35 Comment(3)
strstr is too similiar to strtrClap
strstr needs a strict comparison too Example: ('123450', '0')Steffi
If this was an acceptable answer, then the page should have been closed as opinion-based.Wheal

© 2022 - 2024 — McMap. All rights reserved.