Skip to content

Commit

Permalink
Improve Stream implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Oct 15, 2023
1 parent e7162f9 commit 084073f
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ All Notable changes to `Csv` will be documented in this file
- `TabulatDataReader::firstOrFailMatching`
- `FragmentFinder` to implement [RFC7111](https://www.rfc-editor.org/rfc/rfc7111)
- `ResultSet::fromRecords`
- `Stream::setMaxLineLen`
- `Stream::getMaxLineLen`

### Deprecated

Expand All @@ -26,6 +28,7 @@ It's usage will trigger a `E_USER_DEPRECATED` call.
- `ResultSet` constructor now allows the records to be an `array`.
- to the internal `Stream` object it will throw a `RuntimeException` if the rewind action fails
- if calls to `fseek` fails (returns `-1` ) a new `RuntimeException` will be thrown too.
- `Stream` can iterate and return the full line respecting `SplFielObject` flags. Previously it only returned the CSV records.

### Removed

Expand Down
83 changes: 79 additions & 4 deletions src/Stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use SplFileObject;
use Stringable;
use TypeError;
use ValueError;

use function array_keys;
use function array_walk_recursive;
Expand Down Expand Up @@ -67,6 +68,7 @@ final class Stream implements SeekableIterator
private string $escape = '\\';
/** @var array<string, array<resource>> Attached filters. */
private array $filters = [];
private int $maxLength = 0;

/**
* @param resource $stream stream type resource
Expand Down Expand Up @@ -295,7 +297,7 @@ public function rewind(): void

$this->offset = 0;
$this->value = false;
if (0 !== ($this->flags & SplFileObject::READ_AHEAD)) {
if (SplFileObject::READ_AHEAD === ($this->flags & SplFileObject::READ_AHEAD)) {
$this->current();
}
}
Expand All @@ -308,7 +310,7 @@ public function rewind(): void
public function valid(): bool
{
return match (true) {
0 !== ($this->flags & SplFileObject::READ_AHEAD) => false !== $this->current(),
SplFileObject::READ_AHEAD === ($this->flags & SplFileObject::READ_AHEAD) => false !== $this->current(),
default => !feof($this->stream),
};
}
Expand All @@ -324,24 +326,97 @@ public function current(): mixed
return $this->value;
}

$this->value = $this->getCurrentRecord();
$this->value = match (true) {
SplFileObject::READ_CSV === ($this->flags & SplFileObject::READ_CSV) => $this->getCurrentRecord(),
default => $this->getCurrentLine(),
};

return $this->value;
}

public function fgets(): string|false
{
$arg = [$this->stream];
if (0 < $this->maxLength) {
$arg[] = $this->maxLength;
}
return fgets(...$arg);
}

/**
* Sets the maximum length of a line to be read.
*
* @see https://www.php.net/manual/en/splfileobject.setmaxlinelen.php
*/
public function setMaxLineLen(int $maxLength): void
{
if (0 > $maxLength) {
throw new ValueError(' Argument #1 ($maxLength) must be greater than or equal to 0');
}

$this->maxLength = $maxLength;
}

/**
* Gets the maximum line length as set by setMaxLineLen.
*
* @see https://www.php.net/manual/en/splfileobject.getmaxlinelen.php
*/
public function getMaxLineLen(): int
{
return $this->maxLength;
}

/**
* Tells whether the end of file has been reached.
*
* @see https://www.php.net/manual/en/splfileobject.eof.php
*/
public function eof(): bool
{
return feof($this->stream);
}

/**
* Retrieves the current line as a CSV Record.
*/
private function getCurrentRecord(): array|false
{
$flag = 0 !== ($this->flags & SplFileObject::SKIP_EMPTY);
$flag = SplFileObject::SKIP_EMPTY === ($this->flags & SplFileObject::SKIP_EMPTY);
do {
$ret = fgetcsv($this->stream, 0, $this->delimiter, $this->enclosure, $this->escape);
} while ($flag && is_array($ret) && null === $ret[0]);

return $ret;
}

/**
* Retrieves the current line.
*/
public function getCurrentLine(): string|false
{
$isEmptyLine = SplFileObject::SKIP_EMPTY === ($this->flags & SplFileObject::SKIP_EMPTY);
$dropNewLine = SplFileObject::DROP_NEW_LINE === ($this->flags & SplFileObject::DROP_NEW_LINE);

$arguments = [$this->stream];
if (0 < $this->maxLength) {
$arguments[] = $this->maxLength + 1;
}

do {
$line = fgets(...$arguments);
} while (
(($isEmptyLine || $dropNewLine) && (false !== $line && '' === rtrim($line, "\r\n")))
);

if (false !== $line && $dropNewLine) {
$line = rtrim($line, "\r\n");
}

return $line;
}


/**
* Seeks to specified line.
*
Expand Down

0 comments on commit 084073f

Please sign in to comment.