You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: The file:// stream wrapper changes plain file I/O: feof() is true one read early, and PharData emits a warning #102
While TypePHP is booted, every fopen() / fgets() / feof() in the process goes through TypePHP\Internal\Io\StreamWrapper, including code that is not checked (no include match). Two behaviours differ from PHP's native stream:
1. feof() turns true one read early. The classic read loop loses its last iteration.
Native PHP only reports EOF after a read has hit the end, so the third fgets() happens and returns false. Code that counts lines this way, or that tails the last N lines of a file, gets a different answer when TypePHP is active (we have a component that shows the last N lines of a log: it returns a different window under TypePHP).
2. Creating an archive with PharData emits a warning.
The archive is created correctly, but TypePHP adds:
Warning: fopen(.../archive.tar): Failed to open stream: No such file or directory in .../vendor/typephp/typephp/src/Internal/Io/StreamWrapper.php on line 397
With TYPEPHP_DISABLE=1 there is no warning. PHPUnit marks such tests risky, and any setup that treats PHP warnings as failures fails.
Both tested on v0.10.26, main (88fcb12) and next-minor-released (f617372, PR #100), PHP 8.2, type cache cleared before each run. @fopen() on a missing file is correctly silent, so that part of the wrapper is fine.
Expected output
File I/O through the wrapper behaves like the native plainfiles stream: feof() only true after a read reached the end, and no extra warning when a phar archive is created. Ideally the wrapper only handles the files it actually rewrites (includes matching the config) and leaves other fopen() calls to the native stream.
Context: same codebase as #93 / #99 / #101; this one changes test results without any TypeError, which makes it hard to spot.
This one cannot be reproduced in the playground: both snippets behave natively there (feof() loop gets 3 reads, PharData prints no warning), because the playground does not go through TypePHP\Internal\Io\StreamWrapper. It needs a Composer install with TypePHP booted, as in the steps above.
Activity
fdaviddpt commentedon Oct 4, 2026
This one cannot be reproduced in the playground: both snippets behave natively there (
feof()loop gets 3 reads,PharDataprints no warning), because the playground does not go throughTypePHP\Internal\Io\StreamWrapper. It needs a Composer install with TypePHP booted, as in the steps above.