From b86f463915fcddbabd3f9231b4d5e0f0154a8a94 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Fri, 22 May 2026 10:05:52 +0200 Subject: [PATCH] fix(config): add null coalescing fallback in getValueBool before strtolower Followup to #59646: guard against null reaching strtolower() in both AppConfig and UserConfig getValueBool(). Also aligns AppConfig with the (string) cast added in UserConfig by the original PR. Signed-off-by: skjnldsv --- build/psalm-baseline.xml | 5 ----- lib/private/AppConfig.php | 10 +++++++++- lib/private/Config/UserConfig.php | 14 +++++++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 94563f7664129..a8c6a2e1a33ff 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -3548,11 +3548,6 @@ - - - getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL)]]> - - request->server]]> diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index 40e5a84d8b27f..2e2221ccfb92d 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -437,7 +437,15 @@ public function getValueFloat(string $app, string $key, float $default = 0, bool */ #[\Override] public function getValueBool(string $app, string $key, bool $default = false, bool $lazy = false): bool { - $b = strtolower($this->getTypedValue($app, $key, $default ? 'true' : 'false', $lazy, self::VALUE_BOOL)); + // The explicit (string) cast and ?? null guard defend against a PHP OPcache bug where + // values passed by reference across function boundaries can have their type corrupted + // (e.g. bool returned as int, or null). Affects PHP 8.x with OPcache enabled; fixed + // upstream in https://github.com/php/php-src/pull/21973. Keep until minimum PHP version + // is bumped. Psalm sees the declared return type (string) and flags these as redundant. + /** @psalm-suppress RedundantCondition, TypeDoesNotContainNull */ + $value = $this->getTypedValue($app, $key, $default ? 'true' : 'false', $lazy, self::VALUE_BOOL) ?? ($default ? 'true' : 'false'); + /** @psalm-suppress RedundantCast */ + $b = strtolower((string)$value); return in_array($b, ['1', 'true', 'yes', 'on']); } diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php index 8c551afb5cc31..5ea22730b58d4 100644 --- a/lib/private/Config/UserConfig.php +++ b/lib/private/Config/UserConfig.php @@ -705,11 +705,15 @@ public function getValueBool( bool $default = false, bool $lazy = false, ): bool { - // The explicit (string) cast guards against a PHP OPcache bug where values passed - // by reference across function boundaries can have their type corrupted (e.g. bool - // returned as int). Affects PHP 8.x with OPcache enabled; fixed upstream in - // https://github.com/php/php-src/pull/21973. Keep until minimum PHP version is bumped. - $b = strtolower((string)$this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL)); + // The explicit (string) cast and ?? null guard defend against a PHP OPcache bug where + // values passed by reference across function boundaries can have their type corrupted + // (e.g. bool returned as int, or null). Affects PHP 8.x with OPcache enabled; fixed + // upstream in https://github.com/php/php-src/pull/21973. Keep until minimum PHP version + // is bumped. Psalm sees the declared return type (string) and flags these as redundant. + /** @psalm-suppress RedundantCondition, TypeDoesNotContainNull */ + $value = $this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL) ?? ($default ? 'true' : 'false'); + /** @psalm-suppress RedundantCast */ + $b = strtolower((string)$value); return in_array($b, ['1', 'true', 'yes', 'on']); }