Re: [RFC] CSV Extension (ext/csv)

From: Date: Fri, 09 Oct 2026 08:59:48 +0000
Subject: Re: [RFC] CSV Extension (ext/csv)
References: 1 2  Groups: php.internals 
Request: Send a blank email to internals+get-132848@lists.php.net to get a copy of this message
Hi, Thanks for the feedback! Both are good points. On streams/resources: I agree that supporting already-open streams would be a valuable addition, particularly for reading. For writing, it is already possible to stream rows individually without buffering the entire collection: foreach ($rows as $row) { fwrite($stream, Csv\array_to_row($row)); } However, a dedicated collection_to_stream() would provide a more convenient API, consistent row-width validation, and symmetry with the existing file-based function. For reading, the gap is more significant. Splitting a stream into lines and passing them to row_to_array() is not reliable because enclosed CSV fields may contain line breaks. The parser used by createFromFile() already operates on PHP streams internally, so exposing this functionality for existing stream resources should be relatively straightforward. I'm considering two additional entry points: Csv\collection_to_stream($stream, iterable $collection, ...): void Csv\LazyLaxCollection::createFromStream($stream, ...): LazyLaxCollection I would prefer separate entry points rather than overloading the existing $file parameter to accept both paths and resources. Since PHP does not support resource as a declared parameter type, the stream parameter would be untyped, documented as @param resource, and validated at runtime, with invalid arguments resulting in a TypeError. The intended semantics for createFromStream() would be: - Parsing starts at the stream's current position, allowing callers to skip a BOM or preamble beforehand. - The extension borrows the stream and never closes it. - Repeated iteration seeks back to the position recorded when the collection was created. Non-seekable streams support only a single iteration. - If the caller closes the stream during iteration, subsequent reads should throw an error rather than access freed memory. - Since the parser reads ahead in chunks, the underlying stream's position after partial iteration is not guaranteed to match the end of the last returned row. Mixing reads from the collection with direct reads from the same stream would therefore not be supported. Would these semantics work for your use cases, particularly the read-ahead behavior and separate entry points? On LazyLaxCollection: "Lax" means that rows are not required to contain the same number of fields. This mirrors the distinction between buffer_to_collection(), which throws a ValueError when row widths differ, and buffer_to_collection_lax(), which accepts rows of varying widths. The name comes from the original girgias/csv implementation by Gina Peter Banyard. To make this behavior explicit, I've also added a dedicated PHPT test: ext/csv/tests/LazyCollection/fromBuffer/lax_varying_field_count.phpt. The test verifies that LazyLaxCollection::createFromBuffer() accepts consecutive rows containing 3, 1, 2, and 4 fields, while buffer_to_collection() throws a ValueError for the same input. Naming is already listed as an open issue in the RFC, along with whether a strict lazy variant should be included. Your question reinforces that the current name may not communicate its purpose clearly enough. I'd welcome suggestions here. For example, LazyCollection with configurable strictness could be worth considering. I'll update the RFC once we've had a chance to discuss the API details. Thanks again! Best regards, Damian On Fri, Oct 9, 2026 at 9:03 AM Lynn <kjarli@gmail.com> wrote: > > > On Fri, Oct 9, 2026 at 8:22 AM Damian Jóźwiak < > damian.jozwiak.lodz@gmail.com> wrote: > >> >> Hi internals, >> >> I'd like to open the discussion on an RFC proposing a dedicated CSV >> extension (ext/csv) for PHP core. >> >> RFC: https://wiki.php.net/rfc/csv_extension >> >> Implementation: https://github.com/php/php-src/pull/24199 >> >> The proposal builds upon Gina Peter Banyard's girgias/csv extension >> (BSD-3-Clause), with additional functionality for file and stream handling. >> >> The motivation includes the deprecation of the SplFileObject CSV methods >> in PHP 8.6, which leaves certain use cases without a direct replacement. >> >> The proposed extension provides: >> >> - >> >> Six functions and one class in the Csv\ namespace. >> - >> >> RFC 4180-compatible parsing and serialization by default. >> - >> >> Locale-independent processing without the proprietary escape >> mechanism. >> - >> >> Multibyte delimiters, enclosures, and EOL sequences. >> - >> >> Strict and lax collection parsing. >> - >> >> Lazy iteration over CSV files and streaming output. >> >> The implementation includes PHPT tests covering parsing, serialization, >> stream handling, resource lifetime, and various edge cases. >> >> The pull request's CI checks are currently passing across the tested >> platforms, including debug, ZTS, and AddressSanitizer configurations. >> >> The initial API is deliberately kept small. A more comprehensive >> object-oriented Reader/Writer API, including capability-oriented >> interfaces, is left for potential future discussion. >> >> I'd particularly appreciate feedback on the public API design, the naming >> of LazyLaxCollection, and whether the extension should be always enabled >> or optional at build time. >> >> For transparency, Gina has not reviewed or endorsed this RFC. Parts of >> the implementation were developed with LLM assistance; I have reviewed the >> code and take full responsibility for the contribution. >> >> This is an invitation for discussion, not a call for votes. >> >> Thanks in advance for your feedback. >> >> Best regards, >> Damian Jóźwiak >> > I see that there's no support for open streams/resources, would that be > something worth adding? I don't want to have to write things to a file > before I can start processing them if I already have an open stream. Same > goes for reading, I don't want to have to read everything before passing it > somewhere, often having it as a resource is more useful to me. > > About LazyLaxCollection, what does Lax mean here? >

« previous php.internals (#132848) next »