diff --git a/src/Carbon/CarbonImmutable.php b/src/Carbon/CarbonImmutable.php index 29edbb8..f115c71 100644 --- a/src/Carbon/CarbonImmutable.php +++ b/src/Carbon/CarbonImmutable.php @@ -13,9 +13,15 @@ declare(strict_types=1); namespace Carbon; +use BadMethodCallException; +use Carbon\Exceptions\UnknownMethodException; use Carbon\Traits\Date; use DateTimeImmutable; use DateTimeInterface; +use NoDiscard; +use ReflectionException; +use ReturnTypeWillChange; +use Throwable; /** * A simple API extension for DateTimeImmutable. @@ -839,6 +845,10 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface { use Date { __clone as dateTraitClone; + __call as dateTraitCall; + modify as dateTraitModify; + next as dateTraitNext; + previous as dateTraitPrevious; } public function __clone(): void @@ -848,6 +858,66 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface $this->startOfTime = false; } + /** + * Dynamically handle calls to the class. + * + * @param string $method magic method name called + * @param array $parameters parameters list + * + * @throws UnknownMethodException|BadMethodCallException|ReflectionException|Throwable + */ + #[NoDiscard] + public function __call(string $method, array $parameters): mixed + { + return $this->dateTraitCall($method, $parameters); + } + + /** + * Calls \DateTimeImmutable::modify. + * + * @see https://php.net/manual/en/datetimeimmutable.modify.php + * + * @return static + */ + #[NoDiscard] + #[ReturnTypeWillChange] + public function modify($modify) + { + return $this->dateTraitModify($modify); + } + + /** + * Modify to the next occurrence of a given modifier such as a day of + * the week. If no modifier is provided, modify to the next occurrence + * of the current day of the week. Use the supplied constants + * to indicate the desired dayOfWeek, ex. static::MONDAY. + * + * @param string|int|null $modifier + * + * @return static + */ + #[NoDiscard] + public function next($modifier = null) + { + return $this->dateTraitNext($modifier); + } + + /** + * Modify to the previous occurrence of a given modifier such as a day of + * the week. If no dayOfWeek is provided, modify to the previous occurrence + * of the current day of the week. Use the supplied constants + * to indicate the desired dayOfWeek, ex. static::MONDAY. + * + * @param string|int|null $modifier + * + * @return static + */ + #[NoDiscard] + public function previous($modifier = null) + { + return $this->dateTraitPrevious($modifier); + } + /** * Create a very old date representing start of time. * diff --git a/tests/CarbonImmutable/DiffTest.php b/tests/CarbonImmutable/DiffTest.php index 6a24275..818810b 100644 --- a/tests/CarbonImmutable/DiffTest.php +++ b/tests/CarbonImmutable/DiffTest.php @@ -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')); diff --git a/tests/CarbonImmutable/GenericMacroTest.php b/tests/CarbonImmutable/GenericMacroTest.php index 6a66455..3e323ef 100644 --- a/tests/CarbonImmutable/GenericMacroTest.php +++ b/tests/CarbonImmutable/GenericMacroTest.php @@ -55,7 +55,7 @@ class GenericMacroTest extends AbstractTestCaseWithOldNow $message = null; try { - $now->barBiz(); + $result = $now->barBiz(); } catch (BadMethodCallException $exception) { $message = $exception->getMessage(); } diff --git a/tests/CarbonImmutable/IsTest.php b/tests/CarbonImmutable/IsTest.php index 84805d9..8015835 100644 --- a/tests/CarbonImmutable/IsTest.php +++ b/tests/CarbonImmutable/IsTest.php @@ -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)); } } diff --git a/tests/CarbonImmutable/MacroTest.php b/tests/CarbonImmutable/MacroTest.php index 5aea75e..e3fe888 100644 --- a/tests/CarbonImmutable/MacroTest.php +++ b/tests/CarbonImmutable/MacroTest.php @@ -117,7 +117,7 @@ class MacroTest extends AbstractTestCaseWithOldNow /** @var mixed $date */ $date = Carbon::now(); - $date->nonExistingMacro(); + $result = $date->nonExistingMacro(); } public function testTraitMixin() diff --git a/tests/CarbonImmutable/ModifyTest.php b/tests/CarbonImmutable/ModifyTest.php index e5211b6..622ad16 100644 --- a/tests/CarbonImmutable/ModifyTest.php +++ b/tests/CarbonImmutable/ModifyTest.php @@ -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); } } diff --git a/tests/CarbonImmutable/NoDiscardTest.php b/tests/CarbonImmutable/NoDiscardTest.php new file mode 100644 index 0000000..04150dc --- /dev/null +++ b/tests/CarbonImmutable/NoDiscardTest.php @@ -0,0 +1,62 @@ + + * + * 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')); + } +} diff --git a/tests/CarbonImmutable/SettersTest.php b/tests/CarbonImmutable/SettersTest.php index 5468c0a..c5de1ad 100644 --- a/tests/CarbonImmutable/SettersTest.php +++ b/tests/CarbonImmutable/SettersTest.php @@ -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() diff --git a/tests/CarbonPeriod/GettersTest.php b/tests/CarbonPeriod/GettersTest.php index b868080..6689280 100644 --- a/tests/CarbonPeriod/GettersTest.php +++ b/tests/CarbonPeriod/GettersTest.php @@ -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')); }