Add #[NoDiscard] to CarbonImmutable modify(), next(), previous() and __call()

On PHP 8.5, DateTimeImmutable::modify() warns when its result is
discarded, but CarbonImmutable overrides it and lost the attribute.
Override modify(), next(), previous() and __call() in CarbonImmutable
with #[NoDiscard] so a discarded result warns again. The attribute is
ignored on older PHP versions, and mutable Carbon is unchanged.

Existing immutable tests that discarded results now keep them; in
IsTest::testIsSameMonth this was a real slip, the loop never moved $dt.

Fixes #3377
This commit is contained in:
dualfroz committed 2026-10-03 02:24:35 +02:00
1 parent 8dc8cfa977
commit b3fc145df6
9 files changed
+143 -11

No files matched your search

+2 -2
View File
@@ -1686,7 +1686,7 @@ class DiffTest extends AbstractTestCase
{
$from = Carbon::parse('2021-03-27 20:00 Europe/Warsaw');
$to = Carbon::parse('2021-03-27 20:00 Europe/London');
$from->floatDiffInRealDays($to);
$diff = $from->floatDiffInRealDays($to);
$this->assertSame('2021-03-27 20:00:00 Europe/Warsaw', $from->format('Y-m-d H:i:s e'));
$this->assertSame('2021-03-27 20:00:00 Europe/London', $to->format('Y-m-d H:i:s e'));
@@ -1751,7 +1751,7 @@ class DiffTest extends AbstractTestCase
{
$from = Carbon::parse('2021-03-27 20:00 Europe/Warsaw');
$to = Carbon::parse('2021-03-27 20:00 Europe/London');
$from->floatDiffInUtcDays($to);
$diff = $from->floatDiffInUtcDays($to);
$this->assertSame('2021-03-27 20:00:00 Europe/Warsaw', $from->format('Y-m-d H:i:s e'));
$this->assertSame('2021-03-27 20:00:00 Europe/London', $to->format('Y-m-d H:i:s e'));
+1 -1
View File
@@ -55,7 +55,7 @@ class GenericMacroTest extends AbstractTestCaseWithOldNow
$message = null;
try {
$now->barBiz();
$result = $now->barBiz();
} catch (BadMethodCallException $exception) {
$message = $exception->getMessage();
}
+2 -2
View File
@@ -413,9 +413,9 @@ class IsTest extends AbstractTestCase
$this->assertTrue(Carbon::now()->isSameMonth(Carbon::now()));
$dt = Carbon::now();
for ($year = 1990; $year < Carbon::now()->year; $year++) {
$dt->modify($year.$dt->format('-m-').'01');
$dt = $dt->modify($year.$dt->format('-m-').'01');
$this->assertTrue(Carbon::now()->isSameMonth($dt, false));
$dt->modify($year.$dt->format('-m-').'28');
$dt = $dt->modify($year.$dt->format('-m-').'28');
$this->assertTrue(Carbon::now()->isSameMonth($dt, false));
}
}
+1 -1
View File
@@ -117,7 +117,7 @@ class MacroTest extends AbstractTestCaseWithOldNow
/** @var mixed $date */
$date = Carbon::now();
$date->nonExistingMacro();
$result = $date->nonExistingMacro();
}
public function testTraitMixin()
+1 -1
View File
@@ -249,6 +249,6 @@ class ModifyTest extends AbstractTestCase
'$anchorDay is not compatible with overflow',
));
Carbon::parse('2023-02-28')->addYearsWithOverflow(2, anchorDay: 29);
$date = Carbon::parse('2023-02-28')->addYearsWithOverflow(2, anchorDay: 29);
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
/**
* This file is part of the Carbon package.
*
* (c) Brian Nesbitt <brian@nesbot.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\CarbonImmutable;
use Carbon\Carbon as MutableCarbon;
use Carbon\CarbonImmutable as Carbon;
use ErrorException;
use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhp;
use Tests\AbstractTestCase;
#[RequiresPhp('>=8.5.0')]
class NoDiscardTest extends AbstractTestCase
{
public static function dataForDiscardedCalls(): Generator
{
yield ['modify', ['+1 day']];
yield ['next', []];
yield ['previous', []];
yield ['addDays', [2]];
}
#[DataProvider('dataForDiscardedCalls')]
public function testDiscardedResultTriggersWarning(string $method, array $arguments): void
{
$this->expectException(ErrorException::class);
$this->expectExceptionMessage(
"The return value of method Carbon\\CarbonImmutable::$method() should either be used or intentionally ignored by casting it as (void)",
);
$date = Carbon::parse('2026-10-02 12:00');
$this->withErrorAsException(static function () use ($date, $method, $arguments) {
$date->$method(...$arguments);
});
}
public function testMutableResultCanBeDiscarded(): void
{
$date = MutableCarbon::parse('2026-10-02 12:00');
$this->withErrorAsException(static function () use ($date) {
$date->modify('+1 day');
$date->next();
$date->addDays(2);
});
$this->assertSame('2026-10-12 00:00:00', $date->format('Y-m-d H:i:s'));
}
}
+2 -2
View File
@@ -52,7 +52,7 @@ class SettersTest extends AbstractTestCase
));
$d = Carbon::now();
$d->setHours(Month::February);
$d = $d->setHours(Month::February);
}
public function testMonthEnum()
@@ -74,7 +74,7 @@ class SettersTest extends AbstractTestCase
));
$d = Carbon::parse('2023-10-25 21:14:51');
$d->setMonth(2.5);
$d = $d->setMonth(2.5);
}
public function testMonthFloatPassWithZeroDecimalPart()
+2 -2
View File
@@ -90,7 +90,7 @@ class GettersTest extends AbstractTestCase
{
$period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass);
$period->getStartDate()->subDays(3);
$date = $period->getStartDate()->subDays(3);
$this->assertSame('2012-07-01', $period->getStartDate()->format('Y-m-d'));
}
@@ -99,7 +99,7 @@ class GettersTest extends AbstractTestCase
{
$period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass);
$period->getEndDate()->addDays(3);
$date = $period->getEndDate()->addDays(3);
$this->assertSame('2012-07-15', $period->getEndDate()->format('Y-m-d'));
}