This goes out to Leigh Purdie (5 years ago) and also Dade Brandon (4 months ago)
So i say Leigh posting and though omg i need to change all my fgets to stream_get_line. Then i ran the tests as shown in Leigh Purdie comment His results:
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=stream_get_line($fp,65535,"\n")) { 1; } fclose($fp);'
real 0m1.482s
user 0m1.616s
sys 0m0.152s
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=fgets($fp,65535)) { 1; } fclose($fp);'
real 0m7.281s
user 0m7.392s
sys 0m0.136s
My Results:
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=stream_get_line($fp,65535,"\n")) { 1; } fclose($fp);'
real 0m0.341s
user 0m0.352s
sys 0m0.148s
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=fgets($fp,65535)) { 1; } fclose($fp);'
real 0m4.283s
user 0m4.128s
sys 0m0.448s
My results do show the same issue his results show. But first off PHP has at least gotten about 2-5 times faster then when the tests were first run (or better hardware).
Now to relate to Dade Brandon who states if you use a correct buffer size the perfomance is neck and neck.
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=stream_get_line($fp,21,"\n")) { 1; } fclose($fp);'
real 0m0.336s
user 0m0.412s
sys 0m0.076s
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=fgets($fp,21)) { 1; } fclose($fp);'
real 0m0.312s
user 0m0.364s
sys 0m0.192s
As you can see very close and fgets just coming just a little bit ahead. I suspect that fgets is reading backwards on the buffer or loads everything into its self then trys to figure it out where as a correct set buffer does the trick. Dade Brandon states that fgets lets you know how the line was delimited. stream_get_line lets you choose what you wanna call the delimiter using its 3rd option.
fgets has one more option that is important, you dont have to set the length of the line. So in a case where you may not know the length of the line maybe in handling Http protocol or something else like log lines you can simply leave it off and still get great performance.
$ time yes "This is a test line" | head -1000000 | php -r '$fp=fopen("php://stdin","r"); while($line=fgets($fp)) { 1; } fclose($fp);'
real 0m0.261s
user 0m0.260s
sys 0m0.232s
This is better then with a buffer set.