Re: Problems with the stream API
| From: | Christian Kaps | Date: | Sun, 28 Aug 2011 21:54:11 +0000 |
| Subject: | Re: Problems with the stream API | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-55000@lists.php.net to get a copy of this message | ||
Hi Gustavo,
thanks for your detailed explanation.
Nevertheless it might be useful to document these inconsistent(from the
userland point of view) behavior. Please see my comments inline.
Am 28.08.2011 17:22, schrieb Gustavo Lopes:
> On Sun, 28 Aug 2011 14:29:28 +0100, Christian Kaps
> <christian.kaps@mohiva.com> wrote:
>
>> I have some problems with the stream API. The methods stream_tell and
>> stream_seek works not as expected in some cases.
>>
>> Before reading the next lines, please look at the short
>> gist(https://gist.github.com/1176641).
>>
>> First example:
>>
>> $fp = fopen('mfx://test1', 'w');
>> fwrite($fp, '12345678');
>> fseek($fp, -1, SEEK_CUR);
>> fclose($fp);
>> // stream_seek: $offset = 7
>>
>> If you call fseek with the arguments (-1, SEEK_CUR) then the $offset
>> parameter in the method stream_seek is 7. It seems that the internal API
>> takes the written bytes returned by fwrite and then it subtracts the
>> argument (-1) from it before passing it to stream_seek. For the
>> constants SEEK_SET and SEEK_END, the passed value is the same as defined
>> for the fseek call.
>
> SEEK_CUR seeks are internally converted to SEEK_SET seeks. It's been
> this way since at least 2002:
>
>
> http://svn.php.net/viewvc/php/php-src/trunk/main/streams.c?annotate=96547&pathrev=96547#l582
>
>
> The first thing you should know is that PHP keeps track internally of
> the position of the stream. That's why PHP knows how to convert SEEK_CUR
> -1 to SEEK_SET 7.
>
> The seek type conversion is an arguable decision, but changing this has
> some risks. Consider that some some streams might not respond to
> SEEK_CUR seeks or that they do so defectively. The only advantages I see
> is that it could mitigate the problems of an inaccurate internal
> position (though this happens mostly with internal code that casts the
> stream into e.g. a FILE* and then manipulates the pointer); it would
> also save stream implementations that only support SEEK_CUR from having
> to reconvert the SEEK_SET to SEEK_CUR.
>
This behavior should be documented. The possible values for the "whence"
parameter of the "stream_seek" method should only be SEEK_SET and
SEEK_END. And there should be a hint that the SEEK_CUR seeks are
internally converted to SEEK_SET seeks.
>> The second example:
>>
>> $fp = fopen('mfx://test2', 'w');
>> fwrite($fp, '12345678');
>> fread($fp, 2);
>> fseek($fp, 1, SEEK_CUR);
>> fclose($fp);
>>
>> For this example the stream_seek method gets never be called. The
>> difference here is that fread is called before fseek.
>
> No bug here. This is by design. PHP doesn't read only two bytes from the
> stream, it reads an entire chunk. Once PHP has data buffered and you
> tell it to skip one byte, it can just advance its internal pointer on
> the buffered data; no need to actually call fseek.
>
>
It should be documented that, in some circumstances, the "stream_seek"
method isn't called in response to fseek.
>> The third example:
>>
>> $fp = fopen('mfx://test3', 'w');
>> fwrite($fp, '12345678');
>> fread($fp, 3);
>> ftell($fp);
>> fclose($fp);
>>
>> For this example the stream_tell method gets never be called. It is
>> documented(http://www.php.net/manual/en/streamwrapper.stream-tell.php)
>> that the stream_tell method is called in response to ftell(). But it
>> seems that this method is only be called internally by the stream API.
>>
>> There exists a Bug report at
>> https://bugs.php.net/bug.php?id=30157
>>
>> In one of the comments Pierre says: There is no bug but a feature
>> request which seems to be very discutable.
>>
>
> Again, as the comment on the bug report says, this is by design. PHP
> keeps track internally of the position, so it can just return the
> information it has.
>
> But yes, the documentation is wrong in this respect. stream_tell is only
> called after a seek in order to determine where the seek ended up. In
> the C standard library, you're allowed to seek past the end of the file
> and then write, zeroing everything in between the end of the position
> sought to (or failing to write). In PHP, this convention doesn't apply;
> you're not always allowed to seek to any position.
>
The documentation for "stream_tell" is wrong. This method gets only be
called internally.
What do you think about my suggestions?
Christian