PHP Luminova: File Stream
A lightweight wrapper for PHP file streams that provides safe, object-oriented access to reading, writing, and stream operations.
The File Stream class provides a simple and controlled way to work with file resources in PHP using a stream-based approach.
It wraps a native PHP stream resource and exposes common file operations (such as reading, writing, seeking, and metadata access) through a consistent object-oriented interface. Instead of calling low-level f* functions directly, you interact with the stream safely through the class.
Dynamic method calls are supported via __call(), allowing selected PHP stream functions (like fread, fwrite, and stream_get_contents) to be invoked directly on the instance. A built-in whitelist ensures only safe and expected functions can be executed.
This design helps reduce boilerplate, enforce safer usage, and keep file handling predictable, especially in larger applications.
For HTTP Message Stream see documentation.
Examples
Create Stream
Opens immediately:
$stream = new Stream('/var/data/report.csv', 'rb');
$data = $stream->read();
$stream->close();Deferred open (attach context first):
$ctx = stream_context_create(['http' => ['method' => 'GET']]);
$stream = new Stream('http://example.com/file', 'rb', autoOpen: false);
$stream->setContext($ctx)->open();From Resource
Wrap an existing handle. The stream will not close it.
$fp = fopen('/tmp/shared.log', 'a+b');
$stream = Stream::fromResource($fp);
$stream->lock(LOCK_EX);
$stream->write("entry\n");
$stream->unlock();
fclose($fp);Reopen Stream
Switch mode without a new instance:
$stream = new Stream('/var/log/app.log', 'c+b');
$stream->close();
$stream->open('rb');
echo $stream->read();
$stream->close();Inspection
State and Capability
Always check before I/O:
if (!$stream->isOpen()) {
throw new RuntimeException('Stream is closed.');
}
if ($stream->isSeekable()) {
$stream->seek(0, SEEK_END);
$size = $stream->tell();
$stream->rewind();
}Permissions
Based on open mode:
if (!$stream->isReadable()) {
throw new LogicException('Read not allowed.');
}
if (!$stream->isWritable()) {
throw new LogicException('Write not allowed.');
}Metadata
$size = $stream->size();
$type = $stream->metadata('stream_type');Pointer
$pos = $stream->tell();
$stream->seek(-256, SEEK_END);
$tail = $stream->read(256);Reading
$stream->lock(LOCK_SH);
$stream->rewind();
$content = $stream->read();
$stream->unlock();Line-by-line:
$stream->rewind();
while (!$stream->eof()) {
$line = $stream->readLine();
if ($line === '') break;
}Decoding
echo $stream->toString();
$arr = $stream->toArray();
$obj = $stream->toObject();
if ($stream->isJsonString()) {
// valid JSON
}Writing
Append safely:
$stream->lock(LOCK_EX);
$stream->seek(0, SEEK_END);
$stream->write("new entry\n");
$stream->flush();
$stream->unlock();Write at offset:
$stream->writeAt('PATCHED', offset: 16);Overwrite and Replace
$stream->overwrite(json_encode($config, JSON_PRETTY_PRINT));$stream->replace('level=debug', 'level=info');Truncate
$stream->lock(LOCK_EX);
try {
$stream->truncate(0);
$stream->write($data);
$stream->flush();
} finally {
$stream->unlock();
}Locking
Blocking:
$stream->lock(LOCK_EX);
try {
$stream->write($data);
$stream->flush();
} finally {
$stream->unlock();
}Non-blocking:
$wouldBlock = 0;
try {
$stream->lock(LOCK_SH | LOCK_NB, 1, 0, $wouldBlock);
} catch (RuntimeException $e) {
if ($wouldBlock) {
echo 'Locked by another process.';
}
}Try lock:
if (!$stream->tryLock(LOCK_EX)) {
return;
}
$stream->write($data);
$stream->unlock();Utilities
Copy
$source->rewind();
$source->copy($dest, length: 4096);Checksum
$hash = $stream->checksum('sha256');
$fast = $stream->checksum('xxh3', true);Filtering
$stream->contains('hello');$result = $stream->search('hello');Class Definition
- Class namespace:
Luminova\Storage\Stream - This class implements: Stringable
Properties
resource
The underlying file resource handle, or null when closed.
protected ?resource $resource = null;context
Optional stream context resource created via stream_context_create(), to be use when opening stream.
protected ?resource $context = nullisReadonly
Object-level read-only mode.
protected bool $isReadonly = falseisReadonlyImmutable
Immutable read-only mode.
protected bool $isReadonlyImmutable = false;isOwnsHandler
Whether this instance owns (and is therefore responsible for closing) the handle.
protected bool $isOwnsHandler = true;False when the handle was injected via Stream::fromResource().
allowedDynamicFunctions
Whitelist of allowed dynamic stream functions.
This controls which PHP functions can be called via __call() on the underlying stream resource.
protected ?array<int,string-callable> $allowedDynamicFunctions = [
'fread', 'fwrite', 'fseek', 'ftell', 'fstat',
'rewind', 'feof', 'fgetc', 'fgets', 'fflush',
'ftruncate', 'stream_get_contents'
];Usage:
null→ use default allowed functions (safe defaults, e.g.,fread,fwrite, etc.)[]→ deny all dynamic function calls.[...]→ explicitly allow only the listed functions.
allowedResourceType
Expected resource type (default: stream).
protected string $allowedResourceType = 'stream';filename
The stream filename.
protected string $filename = '';mode
The stream open file mode.
protected string $mode = 'c+b';autoOpen
Auto open stream.
If set to true, stream will attempt to open once object is created.
protected bool $autoOpen = true;Methods
constructor
Creates a new Stream instance and, optionally, opens the underlying file immediately.
Set $autoOpen to false and call setContext() before open() when a custom streamcontext is required, because the context is passed to fopen() at open time.
public __construct(string $filename, string $mode = 'c+b', bool $autoOpen = true): mixedParameters:
| Parameter | Type | Description |
|---|---|---|
$filename | string | The filename or stream URI (e.g. php://temp, compress.zlib://file.gz). |
$mode | string | The fopen-compatible mode string (default: c+b). |
$autoOpen | bool | When true (default) the file is opened in the constructor. Pass false to defer opening until open() is called explicitly. |
Throws:
- \Luminova\Exceptions\RuntimeException - If $autoOpen is true and the file cannot be opened.
from
Create a stream instance from a resource, filename, or raw string content.
This method detects the type of the given source and delegates creation:
resource→ wraps the existing streamstring (filename)→ opens a file stream using the given modestring (non-file)→ creates an in-memory stream from content
public static from(mixed $source, string $mode = 'wb+', bool $readonly = false): staticParameters:
| Parameter | Type | Description |
|---|---|---|
$source | mixed | Stream resource, file path, or raw string content. |
$mode | string | File open mode (used only when source is a file path). |
$readonly | bool | Weather to mark stream as read-only object (default: false). |
Return Value:
static - Return new instance of stream class.
Throws:
- \Luminova\Exceptions\RuntimeException - If the source type is not supported.
fromResource
Wraps an already-open stream resource in a Stream instance without taking ownership.
The returned instance will never call fclose() on the resource; lifetimemanagement stays with the caller.
public static fromResource(resource $resource, string $filename = '', bool $readonly = false): selfParameters:
| Parameter | Type | Description |
|---|---|---|
$resource | resource | A valid, open stream resource. |
$filename | string | Optional filename to associate with the resource (used for error messages only; does not affect I/O). |
$readonly | bool | Weather to mark stream as read-only object (default: false). |
Return Value:
self - A new Stream instance wrapping the supplied resource.
Throws:
- \Luminova\Exceptions\InvalidArgumentException - If $resource is not a valid stream resource.
fromString
Create a read-write Stream from a plain string.
The string is written into a php://temp stream opened with the given mode, the pointer is rewound to position 0, and the stream is returned ready for both reading and writing.
public static fromString(string $content, string $mode = 'wb+', bool $readonly = false): staticParameters:
| Parameter | Type | Description |
|---|---|---|
$content | string | The raw string content to seed the stream with. |
$mode | string | The fopen() mode used to open the stream (default: 'wb+'). |
$readonly | bool | Weather to mark stream as read-only object (default: false). |
Return Value:
static - A new Stream instance containing the given content.
Throws:
- \Luminova\Exceptions\RuntimeException - If the content looks like a filesystem path, or ifthe temporary stream cannot be created.
setBlocking
Set whether the stream operates in blocking mode.
public setBlocking(bool $blocking): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$blocking | bool | True for blocking, false for non-blocking. |
Return Value:
bool - True on success, false on failure.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is closed or operation fails.
setReadOnly
Mark the stream as read-only or writable.
When set to read-only, all write operations (write, truncate, etc.) will be blocked at the API level.
If $immutable is true, the stream becomes permanently read-only and cannot be changed back to writable.
public setReadOnly(bool $readonly, bool $immutable = false): selfParameters:
| Parameter | Type | Description |
|---|---|---|
$readonly | bool | True to make the stream read-only. |
$immutable | bool | True to enforce permanent read-only mode. |
Return Value:
self - Return instance of stream class.
setTimeout
Set the read/write timeout for the stream.
public setTimeout(int $seconds, int $microseconds = 0): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$seconds | int | Timeout seconds. |
$microseconds | int | Timeout microseconds. |
Return Value:
bool - True on success, false on failure.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is closed or operation fails.
setContext
Attaches a stream context to be used the next time open() is called.
Must be called before open() (or before construction when $autoOpen is true).Setting the context after the stream is already open has no effect on the current handle.
public setContext(resource $context): selfParameters:
| Parameter | Type | Description |
|---|---|---|
$context | resource | A context resource created by stream_context_create(). |
Return Value:
self - Return instance of stream class.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is already open.
setResource
Set the underlying stream resource for the wrapper.
This replaces the current stream resource with a new one.
The provided resource must be a valid PHP stream (get_resource_type() === 'stream').If a previous resource exists, it will be closed first.
public setResource(mixed $resource, string $filename = ''): selfParameters:
| Parameter | Type | Description |
|---|---|---|
$resource | mixed | A valid PHP stream resource to wrap. |
$filename | string | Optional filename for the stream. |
Return Value:
self - Returns the current instance for chaining.
Throws:
- \Luminova\Exceptions\InvalidArgumentException - If the provided resource is not a valid stream.
Note:After setting, the wrapper does not “own” the resource,meaning it will not close it automatically unless explicitly told.
setAllowedResourceType
Set the allowed stream resource type for this instance.
This defines the expected resource type for any stream assigned to this wrapper. Only valid PHP stream types are accepted.
public setAllowedResourceType(string $expected): selfParameters:
| Parameter | Type | Description |
|---|---|---|
$expected | string | The expected resource type (e.g., stream). |
Return Value:
self - Returns instance stream class.
Throws:
- \Luminova\Exceptions\InvalidArgumentException - If the provided type is empty or invalid.
getType
Returns the PHP resource type string of the underlying handle, or null if closed.
For a normal file or pipe this returns stream.
public getType(): ?stringReturn Value:
string|null - Resource type string, or null when the handle is closed.
Use
isOpen()to check whether the stream is usable.
getId
Get the internal resource identifier.
Returns the unique ID assigned by PHP to the underlying stream resource,or null if the stream is not initialized.
public getId(): ?intReturn Value:
int|null - Resource ID or null if no resource is available.
getResource
Returns the underlying stream resource.
public getResource(): ?resourceReturn Value:
resource|null - Returns the stream resource, or null if closed.
isOpen
Returns true when the underlying file handle is open and valid.
public isOpen(): boolReturn Value:
bool - Return true if stream is open, otherwise false.
isType
Check if the stream resource matches a specific type.
Compares the actual type of the underlying stream resource with thegiven type string.
public isType(string $type): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$type | string | The expected resource type (e.g., stream, file). |
Return Value:
bool - Return true if the resource type matches, false otherwise.
isReadOnly
Check whether the stream is read-only.
Returns true if the stream is marked as read-only, meaning write operations(such as write, truncate, or overwrite) are not allowed.
public isReadOnly(): boolReturn Value:
bool - True if the stream is read-only, false otherwise.
isSeekable
Returns true when the stream supports random-access seeking.
Non-seekable streams (network sockets, pipes, php://stdin) return false.Calling seek() on a non-seekable stream returns -1 without throwing.
public isSeekable(): boolReturn Value:
bool - true if the stream is seekable, false if it is not orif the stream has been detached.
isReadable
Returns true when the stream mode allows reading.
Detection is based on the mode string: any mode containing r or + isconsidered readable.
Modes like: w, a, x, and c (without +) arewrite-only and return false.
public isReadable(): boolReturn Value:
bool - true if the stream is readable, false otherwise.
isWritable
Returns true when the stream mode allows writing.
Any mode other than plain r (without +) is considered writable. Thisincludes r+, w, w+, a, a+, x, x+, c, c+, and theirbinary (b) variants.
public isWritable(): boolReturn Value:
bool - true if the stream is writable, false otherwise.
isLocked
Returns true when another process (or a non-cooperative thread) currentlyholds an exclusive lock on the stream file.
The check uses a non-blocking LOCK_EX attempt. If the lock is successfullyacquired it is immediately released and false is returned (not locked byothers). If the attempt fails, another holder exists and true is returned.
Note: flock() is per-process on Linux. If this process already holds thelock, the probe will succeed (re-entrant), so isLocked() will return falseeven though the file is locked it only detects external locks.
public isLocked(): boolReturn Value:
bool - True if an external lock is detected, false otherwise.
isJsonString
Check whether the entire stream content is valid JSON.
If the stream is seekable, rewinds to the beginning before validating.Returns false for empty streams, unreadable resources, or invalid JSON.
public isJsonString(int $depth = 512): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$depth | int | Maximum nesting depth of the structure being decoded (default: 512). |
Return Value:
bool - Return true if the stream contains valid JSON, false otherwise.
isFile
Determine whether a string represents an existing filesystem path.
protected isFile(string $input, bool $throw): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$input | string | The filename to evaluate. |
$throw | bool | Weather to throw exception if failed. |
Return Value:
bool - Return true if the input resolves to an existing file =, otherwise false.
Throws:\Luminova\Exceptions\RuntimeException - If failed and $throw is true.
isUrl
Check if fopen target is a valid URL.
Checks for scheme: (http, https, ftp or stream_get_wrappers).And also consider if allow_url_fopen is disabled or not.
protected isUrl(string $path, bool $throw): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$path | string | |
$throw | bool | Weather to throw exception if failed. |
Return Value:
bool - True if valid URL, false otherwise.
Throws:\Luminova\Exceptions\RuntimeException - If failed and $throw is true.
isFopenLike
Loosely detect if a string could be a valid fopen target.
Matches:
- Local paths (absolute or relative)
- Filenames with extensions
- URLs (http, https, ftp)
protected isFopenLike(string $target): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$target | string | The target fopen filename. |
Return Value:
bool - Return true if valid, otherwise false.
open
Opens (or re-opens) the stream using the configured path and mode.
If the stream is already open, close() is called first to preventhandle leaks before the new handle is created.
public open(?string $mode = null): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$mode | string|null | The fopen() mode override. When null the mode passedto the constructor (default c+b) is used. |
Return Value:
bool - Returns true on success (the handle is a valid stream resource).
Throws:
- \Luminova\Exceptions\RuntimeException - If the file cannot be opened.
close
Closes the stream and releases the file handle.
Only closes the handle when this instance owns it (i.e. not injected viafromResource()). After close(), all I/O methods will throw a RuntimeExceptionuntil open() is called again.
public close(): voiddetach
Detach the underlying PHP resource from this stream object.
Once detached the stream is in an unusable state (equivalent to a closed stream), but the caller receives the raw resource and takes full responsibility for closing it.
public detach(): ?resourceReturn Value:
resource|null - The detached resource, or null if the stream has already been detached or closed.
metadata
Retrieves stream metadata, optionally filtered to a single key.
Common keys:
seekable,mode,uri,eofwrapper_type,stream_typetimed_out,blocked,unread_bytes
public metadata(?string $key = null): mixedParameters:
| Parameter | Type | Description |
|---|---|---|
$key | string|null | Metadata key to retrieve. Pass null to get the full array. |
Return Value:
array- Return full metadata array when$keyisnull, empty array if handle is closed.scalar- Return value for a specific key ornullif the key does not exist or the handle is closed;
stat
Returns low-level file statistics for the open stream.
Possible Keys:
'dev', 'ino', 'mode', 'nlink', 'uid', 'gid', 'rdev', 'size', 'atime','mtime', 'ctime', 'blksize', 'blocks'.
public stat(): array<string,int>Return Value:
array<string,int> - Associative fstat array, or empty array on failure.
size
Calculate the byte size of the stream contents.
public size(): intReturn Value:
int - Return the file size in bytes, or -1 if unavailable.
seek
Moves the file pointer to the given byte offset.
Returns 0 on success, -1 on failure or when the stream is not seekable(matching fseek() semantics).
public seek(int $offset, int $whence = SEEK_SET): voidParameters:
| Parameter | Type | Description |
|---|---|---|
$offset | int | Byte position to seek to. Use negative values with SEEK_END to seek from the end of the file. |
$whence | int | One of the SEEK_* constants (default: SEEK_SET).- SEEK_SET — absolute position from the start.- SEEK_CUR — offset relative to the current position.- SEEK_END — offset relative to the end of the stream. |
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream has been detached, is not seekable, or fails.
tell
Returns the current byte offset of the file pointer.
public tell(): intReturn Value:
int - Current position in bytes.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream has been detached or fails.
rewind
Rewinds the file pointer to the beginning of the stream (offset 0).
public rewind(): voidThrows:
- \Luminova\Exceptions\RuntimeException - If the stream has been detached, is not seekable,or if the rewind operation fails.
eof
Returns true when the file pointer is at the end of the stream.
public eof(): boolReturn Value:
bool - Return true if EOF or no resource, otherwise false.
lock
Acquire an advisory file lock with optional retry support.
This method attempts to acquire a shared (read) or exclusive (write) lockon the underlying stream resource using flock().
By default, the call blocks until the lock is acquired.
When LOCK_NB is included in $flags, the call becomes non-blocking and will fail immediatelyif the lock cannot be obtained.
Retry logic applies only to blocking mode. When enabled, the method willretry acquiring the lock up to the specified number of attempts, with anoptional delay between attempts.
public lock(
int $flags,
int $retries = 1,
int $delay = 0,
?int &$wouldBlock = null
): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$flags | int | The lock options: - LOCK_SH: Shared/read lock- LOCK_EX: Exclusive/write lock- LOCK_NB: Optional; enables non-blocking mode |
$retries | int | Number of retry attempts in blocking mode (default: 1). |
$delay | int | Delay in microseconds between retries (default: 0). |
&$wouldBlock | int|null | Set by flock() in non-blocking mode if the lock would block. |
Return Value:
bool - True if the lock was acquired, false otherwise
Throws:
\Luminova\Exceptions\InvalidArgumentException - If neither
LOCK_EXnorLOCK_SHis specified.\Luminova\Exceptions\RuntimeException - If the lock cannot be acquired after retries in blocking mode.
See Also:
- tryLock() - For a dedicated non-throwable lock method.
unlock
Releases any advisory lock held on the stream.
Equivalent to flock($handle, LOCK_UN). Safe to call when no lock is held.
public unlock(): boolReturn Value:
bool - Return true on success, false on failure.
read
Reads from the stream.
When $length is -1 (the default) the entire remaining content from thecurrent pointer position to EOF is returned using stream_get_contents().When $length is positive, exactly $length bytes are read using fread().
public read(int $length = -1): stringParameters:
| Parameter | Type | Description |
|---|---|---|
$length | int | Number of bytes to read, or -1 to read until EOF. |
Return Value:
string - The data read from the stream.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed or the read fails.
readLine
Reads one line from the stream (up to and including the newline character).
Returns an empty string at EOF. When $length is provided,reading stops after $length - 1 bytes even if no newline was encountered,matching fgets() semantics.
public readLine(?int $length = null): stringParameters:
| Parameter | Type | Description |
|---|---|---|
$length | int|null | Maximum number of bytes to read (including the newline). Pass null to use PHP's internal default buffer. |
Return Value:
string - The line read, including the trailing newline if present, or an empty string at EOF.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed or
fgets()fails.
write
Writes data to the stream at the current (or specified) byte offset.
When $offset is non-zero the pointer is first moved to that position viaseek() before writing.
public write(string $data): intParameters:
| Parameter | Type | Description |
|---|---|---|
$data | string | The data to write. |
Return Value:
int - Number of bytes written.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed or
write()fails.
Note:
The
seek()is a no-op on non-seekable streams and$offsetis silently ignored in that case. The method does NOT acquire a lock, callers should lock/unlock around write operations as needed.
writeAt
Writes data to the stream at the current (or specified) byte offset.
When $offset is non-zero the pointer is first moved to that position via seek() before writing.
public writeAt(string $data, int $offset): intParameters:
| Parameter | Type | Description |
|---|---|---|
$data | string | The data to write. |
$offset | int | Byte offset to seek to before writing. 0 (default) writes at the current pointer position without seeking. |
Return Value:
int - Number of bytes written.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed or
write()fails.
overwrite
Overwrites the entire stream content with $data.
This method acquires an exclusive lock, rewinds, truncates to zero, writes $data,flushes, and releases the lock, all internally.
This is the safe, idiomatic way to replace a file's contents in one call.
public overwrite(string $data): intParameters:
| Parameter | Type | Description |
|---|---|---|
$data | string | The new content to write. |
Return Value:
int - Number of bytes written.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed, the lock cannot be acquired,or the write fails.
replace
Performs a search and replace on the entire stream content.
Reads the file under a shared lock, applies str_replace(), and writes theresult back via overwrite() (which acquires an exclusive lock internally).
public replace(array|string $search, array|string $replace): intParameters:
| Parameter | Type | Description |
|---|---|---|
$search | array|string | The value(s) to search for. |
$replace | array|string | The replacement value(s). |
Return Value:
int - Number of bytes written after replacement.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed, a lock cannot be acquired, or any I/O operation fails.
contains
Check if the stream contains the given string.
public contains(string $needle, bool $rewind = true): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$needle | string | The string to search for. |
$rewind | bool | Whether to rewind before searching (default: true). |
Return Value:
bool - True if found, false otherwise.
search
Search for occurrences of a string in the stream.
public search(string $needle, bool $rewind = true, bool $firstOnly = false): arrayParameters:
| Parameter | Type | Description |
|---|---|---|
$needle | string | The string to search for. |
$rewind | bool | Whether to rewind before searching. |
$firstOnly | bool | Stop after the first occurrence match is found. |
Return Value:
array<int,array{line: int, position: int}> - Returns an array of matches with line number and byte position:
[
['line' => 1, 'position' => 15],
['line' => 3, 'position' => 42],
]truncate
Truncates the stream to the given size.
If $size is smaller than the file's current size, the extra data is discarded. If $size is larger, the file is extended with null bytes.
The file pointer is NOT moved after truncation, call rewind() or seek() as required.
public truncate(int $size = 0): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$size | int | Target size in bytes. Defaults to 0 (empty the file). |
Return Value:
bool - True on success, false on failure.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed.
flush
Flushes the output buffers of the stream to the underlying storage device.
Should be called after a sequence of write() calls and before unlock()to ensure data is durably persisted before releasing the lock.
public flush(): boolReturn Value:
bool - True on success, false on failure.
Throws:
- \Luminova\Exceptions\RuntimeException - If the handle is closed.
copy
Copies data from this stream into another stream.
Starts copying from the current pointer of the source. Use rewind()to start from the beginning. The destination pointer ends at the end of written data.
public copy(self $destination, int $length = -1, int $offset = 0): intParameters:
| Parameter | Type | Description |
|---|---|---|
$destination | self | Target stream to copy into. |
$length | int | Maximum bytes to copy. Default -1 copies until EOF. |
$offset | int | Byte offset in the source stream. Default 0 uses current position. |
Return Value:
int - Number of bytes copied.
Throws:
- \Luminova\Exceptions\RuntimeException - If the source or destination is closed or copy fails.
buffer
Read the entire stream content, always starting from the beginning.
If the stream is seekable the pointer is rewound to position 0 beforereading, so previously consumed content is included in the result.For non-seekable streams only the remaining (unread) bytes are returned.
public buffer(): stringReturn Value:
string - The complete stream content (or remaining content for non-seekable streams).
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream cannot be read.
checksum
Generate a hash checksum of the entire stream content.
The stream pointer will be rewound before reading if the stream is seekable.For non-seekable streams, hashing is performed from the current position.
public checksum(string $algo = 'xxh3', bool $binary = false): stringParameters:
| Parameter | Type | Description |
|---|---|---|
$algo | string | Hash algorithm (e.g. xxh3, sha256, md5). |
$binary | bool | Whether to return raw binary output. |
Return Value:
string - Return generated hash string.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is invalid, not open, or hashing fails.
tryLock
Attempt to acquire a non-blocking advisory file lock.
This is a fail-fast wrapper around lock() that always operatesin non-blocking mode. It will attempt to acquire the lock once and returnimmediately.
Unlike lock(), this method does not throw an exception on failure.Instead, it returns false if the lock cannot be obtained.
public tryLock(
int $flags,
int $retries = 1,
int $delay = 0,
?int &$wouldBlock = null
): boolParameters:
| Parameter | Type | Description |
|---|---|---|
$flags | int | Lock type: LOCK_SH (shared/read) or LOCK_EX (exclusive/write). OCK_NB is automatically applied and does not need to be passed. |
$retries | int | Ignored in non-blocking mode (default: 1) |
$delay | int | Ignored in non-blocking mode (default: 0) |
&$wouldBlock | int|null | Set to 1 if the lock could not be acquired because it would block. |
Return Value:
bool - True if the lock was acquired, false otherwise.
Throws:
- \Luminova\Exceptions\InvalidArgumentException - If neither LOCK_EX nor LOCK_SH is specified.
toString
Returns the full stream contents as a string, rewinding first.
This method rewinds before reading so callers alwaysget the complete content regardless of the current pointer position.
public toString(): stringReturn Value:
string - Stream contents, or empty string on failure (safe for exception-free contexts).
Same as
__toString()
toObject
Decode the stream content into a JSON object (stdClass).
Returns null if the buffer is empty, invalid JSON, or not an object at the root.
public toObject(int $depth = 512, int $flags = JSON_BIGINT_AS_STRING): ?objectParameters:
| Parameter | Type | Description |
|---|---|---|
$depth | int | Maximum nesting depth of the structure being decoded (default: 512). |
$flags | int | Optional decoding flags (default: JSON_BIGINT_AS_STRING). |
Return Value:
object|null - Decoded object, or null on failure.
toArray
Decode the stream content into a JSON associative array.
Returns an empty array for empty streams. Returns the raw content wrappedin an array if JSON validation fails.
public toArray(int $depth = 512, int $flags = JSON_BIGINT_AS_STRING): arrayParameters:
| Parameter | Type | Description |
|---|---|---|
$depth | int | Maximum nesting depth of the structure being decoded (default: 512). |
$flags | int | Optional decoding flags (default: JSON_BIGINT_AS_STRING). |
Return Value:
array - Decoded array, or array with raw content on invalid JSON.
assertResource
Ensure the stream resource is valid.
protected assertResource(): voidThrows:
- \Luminova\Exceptions\RuntimeException - If the resource is closed or invalid.
Use
isOpen()when you need a non-throwing check.
assertResourceType
Ensure the resource type matches the expected type.
protected assertResourceType(): voidThrows:
- \Luminova\Exceptions\RuntimeException - If the resource type does not match.
Use
isType()when you need a non-throwing check.
assertReadable
Ensure the stream is readable.
protected assertReadable(?string $prefix = null): voidThrows an exception if the underlying resource cannot be read.
Parameters:
| Parameter | Type | Description |
|---|---|---|
$prefix | string|null | Optional message prefix for context. |
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is not readable.
Use
isReadable()when you need a non-throwing check.
assertWritable
Ensure the stream is writable.
This checks both the internal read-only flag and the underlyingresource capability.
protected assertWritable(?string $prefix = null): voidParameters:
| Parameter | Type | Description |
|---|---|---|
$prefix | string|null | Optional message prefix for context. |
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is read-only or not writable.
Use isWritable() or isReadOnly() when you need a non-throwing check.
assertNewResource
Validate that the given resource is a valid PHP stream.
This static helper ensures that the provided resource is a PHP stream(i.e., get_resource_type() === 'stream'). It is intended for usebefore assigning or wrapping a new stream resource.
protected static assertNewResource(mixed $resource, string $expected = 'stream'): voidParameters:
| Parameter | Type | Description |
|---|---|---|
$resource | mixed | The resource to validate. |
$expected | string | The expected resource type (default: 'stream'). |
Throws:
- \Luminova\Exceptions\InvalidArgumentException - If the resource is not a valid stream.
assertFopenTarget
Validate that the given is a valid fopen() target.
Validate:URL, File or registered stream wrapper.
protected assertFopenTarget(string $filename): voidParameters:
| Parameter | Type | Description |
|---|---|---|
$filename | string | The filename to validate. |
Throws:\Luminova\Exceptions\RuntimeException - If not a valid target fopen.
newStatic
Override to create and return new stream instance.
This method is called internally by parent class Luminova\Storage\Stream, when new object need to be created.static::newStatic() is called, instead of new static(...).
This should be based on sub class
__construct()signature that align with parent constructor signature.
protected static newStatic(string $filename, string $mode = 'c+b', bool $autoOpen = true): staticParameters:
| Parameter | Type | Description |
|---|---|---|
$filename | string | The filename to open stream. |
$mode | string | File open mode (used only when source is a file path). |
$autoOpen | bool | When true the file is opened immediately. |
Return Value:
static - Return new instance of stream class.
Example:s
Override newStatic() when your subclass modifies the constructor or needs to control how new instances are created.
use Luminova\Storage\Stream;
class CustomStream extends Stream
{
protected string $prefix;
public function __construct(
string $filename,
string $mode = 'c+b',
string $prefix = ''
) {
// parent::__construct($filename, $mode, false);
$this->prefix = $prefix;
}
/**
* Create a new instance of the current stream class.
*/
protected static function newStatic(
string $filename,
string $mode = 'c+b',
bool $autoOpen = true
): static
{
// Ensure constructor signature is respected
$instance = new static($filename, $mode, false, '[LOG]');
if($autoOpen){
$instance->open();
}
return $instance;
}
}Internal Usage
This method is typically used internally when duplicating or creating a new stream instance:
$stream = CustomStream::fromString('Hello world!', 'c+b');
// Internally creates a new instance of the same class
$newStream = CustomStream::newStatic($this->filename, $this->mode, $this->autoOpen);__call
Dynamically calls a callable function on the underlying stream resource.
The function must be callable and expects the stream resource as its first argument.Any additional arguments are passed as subsequent parameters.
Default Allowed Functions:
fread,fwrite,stream_get_contentsfseek,ftell,rewindfgetc,fgets,feoffstat,fflush,ftruncate
To controller or disabled dynamic f-functions see Allowed Dynamic Functions Property.
public __call(string $fn, array<int,mixed> $arguments): mixedParameters:
| Parameter | Type | Description |
|---|---|---|
$fn | string | Name of the callable function (e.g., stream_get_contents). |
$arguments | array | Additional arguments to pass to the function. |
Return Value:
mixed - The result of the function call.
Throws:
- \Luminova\Exceptions\RuntimeException - If the stream is closed, invalid, or the function is not callable.
Example:
Read entire stream.
$stream = new Stream('file.txt');
// Calls: stream_get_contents($resource)
$content = $stream->stream_get_contents();
echo $content;
// Read fixed number of bytes.
$data = $stream->fread(100);
// Move pointer and read
$stream->fseek(10);
$data = $stream->fread(20);
// Get stream metadata
$info = $stream->fstat();
print_r($info);
// Write to stream
$stream->fwrite("Hello");
$stream->fflush();Custom allowed functions
// Allow only read operations
$stream->allowedDynamicFunctions = ['fread', 'stream_get_contents'];
// Allowed
$content = $stream->stream_get_contents();
// Not allowed (throws RuntimeException)
$stream->fwrite("Blocked");Disable all dynamic calls
// Deny all
$stream->allowedDynamicFunctions = [];
// Any dynamic call will fail
$stream->fread(10); // RuntimeExceptionImportant Notes
- The method automatically injects the stream resource as the first argument
- Only functions that accept a resource as the first parameter are valid
- Invalid or disallowed calls will throw a
Luminova\Exceptions\RuntimeException- This feature is powerful, but don’t treat it like a free-for-all, keep the whitelist tight