From aea5f5170c314e0ddf0e0487685329d8855311e1 Mon Sep 17 00:00:00 2001 From: PurHur Date: Mon, 17 Aug 2026 04:14:21 +0000 Subject: [PATCH] SPL: SplFileObject::setFlags(null) soft-null E_DEPRECATED (#31796) Use Z_PARAM_LONG soft-null coercion so null flags deprecates and stores 0 like php-src, instead of silent toInt(). Co-authored-by: Cursor --- ext/spl/SplFileObjectBuiltin.php | 10 +- phpunit.xml.dist | 1 + ...lFileObjectSetFlagsNullSoft31796VMTest.php | 20 +++ .../spl/splfileobject_setflags_null_soft.phpt | 27 ++++ ...ssue31796SplFileObjectSetFlagsNullTest.php | 115 ++++++++++++++++++ 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php create mode 100644 test/compliance/cases/spl/splfileobject_setflags_null_soft.phpt create mode 100644 test/unit/Issue31796SplFileObjectSetFlagsNullTest.php diff --git a/ext/spl/SplFileObjectBuiltin.php b/ext/spl/SplFileObjectBuiltin.php index 3bdacc48195..9fdf22a7dbb 100644 --- a/ext/spl/SplFileObjectBuiltin.php +++ b/ext/spl/SplFileObjectBuiltin.php @@ -1202,9 +1202,15 @@ public function execute(Frame $frame): void SplFileObjectBuiltin::CLASS_LC, 'SplFileObject::setFlags()' ); - // php-src zim_SplFileObject_setFlags — exactly 1 user arg (#31008). + // php-src zim_SplFileObject_setFlags — ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG (#31796). $this->requireExactUserArgCount($frame, 'SplFileObject::setFlags', 1); - $flags = $frame->calledArgs[1]->resolveIndirect()->toInt(); + $flags = VmMath::parseZParamLongBuiltinArgForFrame( + $frame, + 1, + 'SplFileObject::setFlags', + 1, + 'flags' + ); SplFileObjectStorage::setFlags($object, $flags); } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a86304c0e99..a1fa86b417e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -798,6 +798,7 @@ ./test/compliance/SplFileObjectExcessArgc30937JITTest.php ./test/compliance/SplFileObjectExcessArgc31008VMTest.php ./test/compliance/SplFileObjectExcessArgc31008JITTest.php + ./test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php ./test/compliance/DirItExcessArgc31009VMTest.php ./test/compliance/DirItExcessArgc31009JITTest.php ./test/compliance/RiiGlobExcessArgc31010VMTest.php diff --git a/test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php b/test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php new file mode 100644 index 00000000000..5f4f0766f0d --- /dev/null +++ b/test/compliance/SplFileObjectSetFlagsNullSoft31796VMTest.php @@ -0,0 +1,20 @@ + [$name, $code, $sections]; + } +} diff --git a/test/compliance/cases/spl/splfileobject_setflags_null_soft.phpt b/test/compliance/cases/spl/splfileobject_setflags_null_soft.phpt new file mode 100644 index 00000000000..6afdbb4443c --- /dev/null +++ b/test/compliance/cases/spl/splfileobject_setflags_null_soft.phpt @@ -0,0 +1,27 @@ +--TEST-- +SplFileObject::setFlags(null) — soft-null DEP then flags=0 (#31796) +--FILE-- +setFlags(null); + echo 'flags=' . $f->getFlags() . "\n"; +} catch (Throwable $e) { + echo get_class($e) . ': ' . $e->getMessage() . "\n"; +} +@unlink($tmp); +?> +--EXPECT-- +DEP:SplFileObject::setFlags(): Passing null to parameter #1 ($flags) of type int is deprecated +flags=0 diff --git a/test/unit/Issue31796SplFileObjectSetFlagsNullTest.php b/test/unit/Issue31796SplFileObjectSetFlagsNullTest.php new file mode 100644 index 00000000000..37254da6f78 --- /dev/null +++ b/test/unit/Issue31796SplFileObjectSetFlagsNullTest.php @@ -0,0 +1,115 @@ +runBin('bin/vm.php', $this->softProbeCode()); + $this->assertSame($this->expectedSoftOutput(), $out); + } + + public function testJitSetFlagsNullDeprecationThenZero(): void + { + $out = $this->runBin('bin/jit.php', $this->softProbeCode()); + $this->assertSame($this->expectedSoftOutput(), $out); + } + + public function testVmStrictTypesSetFlagsNullTypeError(): void + { + $out = $this->runBin('bin/vm.php', $this->strictProbeCode()); + $this->assertSame( + "TypeError: SplFileObject::setFlags(): Argument #1 (\$flags) must be of type int, null given\n", + $out + ); + } + + private function expectedSoftOutput(): string + { + return "DEP:SplFileObject::setFlags(): Passing null to parameter #1 (\$flags) of type int is deprecated\n" + ."flags=0\n"; + } + + private function softProbeCode(): string + { + return <<<'PHP' +setFlags(null); + echo 'flags=' . $f->getFlags() . "\n"; +} catch (Throwable $e) { + echo get_class($e) . ': ' . $e->getMessage() . "\n"; +} +@unlink($tmp); +PHP; + } + + private function strictProbeCode(): string + { + return <<<'PHP' +setFlags(null); + echo "ok\n"; +} catch (Throwable $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} +@unlink($tmp); +PHP; + } + + private function runBin(string $bin, string $code): string + { + $repo = dirname(__DIR__, 2); + $tmp = tempnam(sys_get_temp_dir(), 'phpc_31796_'); + $this->assertNotFalse($tmp); + file_put_contents($tmp, $code); + $env = $_ENV; + LlvmToolchain::applyProcessEnv($env, $repo); + $proc = proc_open( + ['php', $repo.'/'.$bin, $tmp], + [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], + $pipes, + $repo, + $env + ); + $this->assertIsResource($proc); + fclose($pipes[0]); + $stdout = stream_get_contents($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[1]); + fclose($pipes[2]); + $exit = proc_close($proc); + @unlink($tmp); + $this->assertSame(0, $exit, $stdout.$stderr); + + return $stdout; + } +}