Skip to content

ext/spl: Fix default argument handling for named parameters in SplFileObject::fgetcsv()#22160

Open
arshidkv12 wants to merge 3 commits into
php:masterfrom
arshidkv12:csv-1
Open

ext/spl: Fix default argument handling for named parameters in SplFileObject::fgetcsv()#22160
arshidkv12 wants to merge 3 commits into
php:masterfrom
arshidkv12:csv-1

Conversation

@arshidkv12
Copy link
Copy Markdown
Contributor

@devnexen
Copy link
Copy Markdown
Member

devnexen commented May 27, 2026

Hi @arshidkv12 thanks for looking into but I m afraid it's more a band aid than a fix (and even it is incomplete). e.g. ; is not the only valid csv separator.

@arshidkv12
Copy link
Copy Markdown
Contributor Author

You are correct. I think this should be changed in the stub.php file. Then manually assign the default value if it is null..

public function fgetcsv(string $separator, string $enclosure, string $escape): array|false {}

@devnexen
Copy link
Copy Markdown
Member

A few suggested tests to add so the brittleness of the current approach is visible in CI.

  1. Explicit , after a non-comma setCsvControl (the false-negative the guard creates).**
$f->setCsvControl(';', "\n", "\\");
$f->fwrite("a,b;c\n");
$f->seek(0);
var_dump($f->fgetcsv(',', '"', '\\'));   // user explicitly wants ,
// expected: ["a","b;c"]   patched: ["a,b","c"]   ← regression introduced by this PR

2. Enclosure-only via named arg (the bug is unfixed on enclosure).
$f->setCsvControl(',', "'", "\\");
$f->fwrite("a,'b,c'\n");
$f->seek(0);
var_dump($f->fgetcsv(escape: '\\'));     // named-skip fills enclosure with "
// expected: ["a","b,c"]   patched: ["a","'b","c'"]

3. Escape via named arg with a non-default enclosure (also exercises the is_escape_default deprecation path).
$f->setCsvControl(',', "'");
$f->fwrite("a,'b\\'c'\n");
$f->seek(0);
var_dump($f->fgetcsv(escape: '\\'));     // enclosure silently becomes "

4. Same bug shape on fputcsv() (the PR does not touch it).
$f->setCsvControl(';', "\n", "\\");
$f->fputcsv(['a','b'], escape: '\\');
$f->seek(0);
echo $f->fgets();                         // expected "a;b\n"   patched: "a,b\n"

5. Reflection round-trip to lock the API contract.
$rm = new ReflectionMethod(SplFileObject::class, 'fgetcsv');
foreach ($rm->getParameters() as $p) {
    var_dump($p->getName(), $p->allowsNull(), $p->getDefaultValue());
}

6. is_escape_default invariant. After setCsvControl(',', '"') (two args), fgetcsv() (no args) should still emit the escape-default deprecation. Confirms the rewrite
does not accidentally suppress the existing notice through the nullability change.

Two meta-points:
- The PR's own test calls setCsvControl(';', "\n", "\\") (three args), which flips is_escape_default to false and hides cases 3 and 6. Dropping the third arg from
setCsvControl already changes what is exercised, so both shapes are worth covering.
- Worth a quick run against the standalone fgetcsv() / fputcsv() in ext/standard as well, just to confirm those are unaffected (no instance state to clobber there),
so the fix scope is correctly limited to the SPL methods.

Note: suggested test cases with help of LLM.

@devnexen
Copy link
Copy Markdown
Member

For final review, might be best to wait Gina's opinion not enough familiar with this part of the code :)

@arshidkv12 arshidkv12 requested a review from kocsismate as a code owner May 27, 2026 12:58
@arshidkv12
Copy link
Copy Markdown
Contributor Author

I can fix fputcsv after completing this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants