Repository: briannesbitt/Carbon (php)

Issue:
Using named parameters of bugs
The author hello
When using named parameters, I met a strange question
Example 1
(`addDays()` and `addHours()` Using named parameters)
```php
di(Notifier::class)->report([
    'currented_at' => $this->now->copy()->format(format: 'Y-m-d H:i:s'),
    'ended_at_1' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_1' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDay()->startOfDay()->addHours(value: 12)->format(format: 'Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDay()->startOfDay()->addHours(value: 12)),
        'pct' => '30%'
    ],
    'ended_at_2' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_2' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDays(value: 2)->startOfDay()->addHours(value: 12)->format('Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDays(value: 2)->startOfDay()->addHours(value: 12)),
        'pct' => '60%',
    ],
    'ended_at_3' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_3' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDays(value: 3)->startOfDay()->addHours(value: 12)->format('Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDays(value: 3)->startOfDay()->addHours(value: 12)),
        'pct' => '100%',
    ],
    'overtime_4' => $this->renewalEndedAt->copy()->format('Y-m-d H:i:s'),
], 'rules');
```
Result 1 (Error)
```php
currented_at: 2022-11-19 21:26:16
ended_at_1: 2022-11-18 22:00:00
overtime_1: array (
  'benchmark' => '2022-11-19 01:00:00',
  'result' => true,
  'pct' => '30%',
)
ended_at_2: 2022-11-18 22:00:00
overtime_2: array (
  'benchmark' => '2022-11-19 01:00:00',
  'result' => true,
  'pct' => '60%',
)
ended_at_3: 2022-11-18 22:00:00
overtime_3: array (
  'benchmark' => '2022-11-19 01:00:00',
  'result' => true,
  'pct' => '100%',
)
ended_at_4: 2022-11-18 22:00:00
```

Example 2
(`addDays()` and `addHours()` Do not use named parameters)
```php
di(Notifier::class)->report([
    'currented_at' => $this->now->copy()->format(format: 'Y-m-d H:i:s'),
    'ended_at_1' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_1' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDay()->startOfDay()->addHours(12)->format(format: 'Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDay()->startOfDay()->addHours(12)),
        'pct' => '30%'
    ],
    'ended_at_2' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_2' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDays(2)->startOfDay()->addHours(value: 12)->format('Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDays(2)->startOfDay()->addHours(12)),
        'pct' => '60%',
    ],
    'ended_at_3' => $this->renewalEndedAt->copy()->format(format: 'Y-m-d H:i:s'),
    'overtime_3' => [
        'benchmark' => $this->renewalEndedAt->copy()->addDays(3)->startOfDay()->addHours(12)->format('Y-m-d H:i:s'),
        'result' => $this->now->copy()->gte(date: $this->renewalEndedAt->copy()->addDays(3)->startOfDay()->addHours(12)),
        'pct' => '100%',
    ],
    'overtime_4' => $this->renewalEndedAt->copy()->format('Y-m-d H:i:s'),
], 'rules');
```
Result 2 (Correct)
```php
currented_at: 2022-11-19 21:26:16
ended_at_1: 2022-11-18 22:00:00
overtime_1: array (
  'benchmark' => '2022-11-19 12:00:00',
  'result' => true,
  'pct' => '30%',
)
ended_at_2: 2022-11-18 22:00:00
overtime_2: array (
  'benchmark' => '2022-11-20 12:00:00',
  'result' => true,
  'pct' => '60%',
)
ended_at_3: 2022-11-18 22:00:00
overtime_3: array (
  'benchmark' => '2022-11-21 12:00:00',
  'result' => true,
  'pct' => '100%',
)
ended_at_4: 2022-11-18 22:00:00
```
Thanks!


Pull request:
Allow named parameters in magic calls
Fix #2708

Patch:
diff --git a/src/Carbon/CarbonInterval.php b/src/Carbon/CarbonInterval.php
index b5e95c51..566b4f94 100644
--- a/src/Carbon/CarbonInterval.php
+++ b/src/Carbon/CarbonInterval.php
@@ -22,6 +22,7 @@ use Carbon\Exceptions\UnknownSetterException;
 use Carbon\Exceptions\UnknownUnitException;
 use Carbon\Traits\IntervalRounding;
 use Carbon\Traits\IntervalStep;
+use Carbon\Traits\MagicParameter;
 use Carbon\Traits\Mixin;
 use Carbon\Traits\Options;
 use Carbon\Traits\ToStringFormat;
@@ -185,6 +186,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
 {
     use IntervalRounding;
     use IntervalStep;
+    use MagicParameter;
     use Mixin {
         Mixin::mixin as baseMixin;
     }
@@ -1360,11 +1362,15 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
         }
 
         if (preg_match('/^(?<method>add|sub)(?<unit>[A-Z].*)$/', $method, $match)) {
-            return $this->{$match['method']}($parameters[0], $match['unit']);
+            $value = $this->getMagicParameter($parameters, 0, Carbon::pluralUnit($match['unit']), 0);
+
+            return $this->{$match['method']}($value, $match['unit']);
         }
 
+        $value = $this->getMagicParameter($parameters, 0, Carbon::pluralUnit($method), 1);
+
         try {
-            $this->set($method, \count($parameters) === 0 ? 1 : $parameters[0]);
+            $this->set($method, $value);
         } catch (UnknownSetterException $exception) {
             if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) {
                 throw new BadFluentSetterException($method, 0, $exception);
diff --git a/src/Carbon/CarbonPeriod.php b/src/Carbon/CarbonPeriod.php
index dbf5eb1b..36f04bf5 100644
--- a/src/Carbon/CarbonPeriod.php
+++ b/src/Carbon/CarbonPeriod.php
@@ -1685,54 +1685,80 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
             return $roundedValue;
         }
 
-        $first = \count($parameters) >= 1 ? $parameters[0] : null;
-        $second = \count($parameters) >= 2 ? $parameters[1] : null;
-
         switch ($method) {
             case 'start':
             case 'since':
-                return $this->setStartDate($first, $second);
+                self::setDefaultParameters($parameters, [
+                    [0, 'date', null],
+                ]);
+
+                return $this->setStartDate(...$parameters);
 
             case 'sinceNow':
-                return $this->setStartDate(new Carbon(), $first);
+                return $this->setStartDate(new Carbon(), ...$parameters);
 
             case 'end':
             case 'until':
-                return $this->setEndDate($first, $second);
+                self::setDefaultParameters($parameters, [
+                    [0, 'date', null],
+                ]);
+
+                return $this->setEndDate(...$parameters);
 
             case 'untilNow':
-                return $this->setEndDate(new Carbon(), $first);
+                return $this->setEndDate(new Carbon(), ...$parameters);
 
             case 'dates':
             case 'between':
-                return $this->setDates($first, $second);
+                self::setDefaultParameters($parameters, [
+                    [0, 'start', null],
+                    [1, 'end', null],
+                ]);
+
+                return $this->setDates(...$parameters);
 
             case 'recurrences':
             case 'times':
-                return $this->setRecurrences($first);
+                self::setDefaultParameters($parameters, [
+                    [0, 'recurrences', null],
+                ]);
+
+                return $this->setRecurrences(...$parameters);
 
             case 'options':
-                return $this->setOptions($first);
+                self::setDefaultParameters($parameters, [
+                    [0, 'options', null],
+                ]);
+
+                return $this->setOptions(...$parameters);
 
             case 'toggle':
-                return $this->toggleOptions($first, $second);
+                self::setDefaultParameters($parameters, [
+                    [0, 'options', null],
+                ]);
+
+                return $this->toggleOptions(...$parameters);
 
             case 'filter':
             case 'push':
-                return $this->addFilter($first, $second);
+                return $this->addFilter(...$parameters);
 
             case 'prepend':
-                return $this->prependFilter($first, $second);
+                return $this->prependFilter(...$parameters);
 
             case 'filters':
-                return $this->setFilters($first ?: []);
+                self::setDefaultParameters($parameters, [
+                    [0, 'filters', []],
+                ]);
+
+                return $this->setFilters(...$parameters);
 
             case 'interval':
             case 'each':
             case 'every':
             case 'step':
             case 'stepBy':
-                return $this->setDateInterval($first);
+                return $this->setDateInterval(...$parameters);
 
             case 'invert':
                 return $this->invertDateInterval();
@@ -1755,9 +1781,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
                 return $this->setDateInterval((
                     // Override default P1D when instantiating via fluent setters.
                     [$this->isDefaultInterval ? new CarbonInterval('PT0S') : $this->dateInterval, $method]
-                )(
-                    \count($parameters) === 0 ? 1 : $first
-                ));
+                )(...$parameters));
         }
 
         if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) {
@@ -2650,4 +2674,13 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
 
         return new $class($date->format('Y-m-d H:i:s.u'), $date->getTimezone());
     }
+
+    private static function setDefaultParameters(array &$parameters, array $defaults): void
+    {
+        foreach ($defaults as [$index, $name, $value]) {
+            if (!\array_key_exists($index, $parameters) && !\array_key_exists($name, $parameters)) {
+                $parameters[$index] = $value;
+            }
+        }
+    }
 }
diff --git a/src/Carbon/Traits/Date.php b/src/Carbon/Traits/Date.php
index 750516a0..da3775c2 100644
--- a/src/Carbon/Traits/Date.php
+++ b/src/Carbon/Traits/Date.php
@@ -532,6 +532,7 @@ trait Date
     use Creator;
     use Difference;
     use Macro;
+    use MagicParameter;
     use Modifiers;
     use Mutability;
     use ObjectInitialisation;
@@ -2669,7 +2670,7 @@ trait Date
         }
 
         if (static::isModifiableUnit($unit)) {
-            return $this->{"{$action}Unit"}($unit, $parameters[0] ?? 1, $overflow);
+            return $this->{"{$action}Unit"}($unit, $this->getMagicParameter($parameters, 0, 'value', 1), $overflow);
         }
 
         $sixFirstLetters = substr($unit, 0, 6);
@@ -2708,7 +2709,11 @@ trait Date
             try {
                 $unit = static::singularUnit(substr($method, 0, -5));
 
-                return $this->range($parameters[0] ?? $this, $parameters[1] ?? 1, $unit);
+                return $this->range(
+                    $this->getMagicParameter($parameters, 0, 'endDate', $this),
+                    $this->getMagicParameter($parameters, 1, 'factor', 1),
+                    $unit
+                );
             } catch (InvalidArgumentException $exception) {
                 // Try macros
             }
diff --git a/src/Carbon/Traits/MagicParameter.php b/src/Carbon/Traits/MagicParameter.php
new file mode 100644
index 00000000..310a44d0
--- /dev/null
+++ b/src/Carbon/Traits/MagicParameter.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * 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 Carbon\Traits;
+
+/**
+ * Trait MagicParameter.
+ *
+ * Allows to retrieve parameter in magic calls by index or name.
+ */
+trait MagicParameter
+{
+    private function getMagicParameter(array $parameters, int $index, string $key, $default)
+    {
+        if (\array_key_exists($index, $parameters)) {
+            return $parameters[$index];
+        }
+
+        if (\array_key_exists($key, $parameters)) {
+            return $parameters[$key];
+        }
+
+        return $default;
+    }
+}


Test patch:
diff --git a/tests/CarbonImmutable/ModifyTest.php b/tests/CarbonImmutable/ModifyTest.php
index f2dbf289..cac4ca4a 100644
--- a/tests/CarbonImmutable/ModifyTest.php
+++ b/tests/CarbonImmutable/ModifyTest.php
@@ -25,6 +25,17 @@ class ModifyTest extends AbstractTestCase
         $this->assertSame(24, $a->diffInHours($b));
     }
 
+    public function testSimpleModifyWithNamedParameter()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $a = new Carbon('2014-03-30 00:00:00');
+        $b = eval('return $a->addHours(value: 24);');
+        $this->assertSame(24, $a->diffInHours($b));
+    }
+
     public function testTimezoneModify()
     {
         // For daylight saving time reason 2014-03-30 0h59 is immediately followed by 2h00
diff --git a/tests/CarbonInterval/AddTest.php b/tests/CarbonInterval/AddTest.php
index eb990de6..7e49fadc 100644
--- a/tests/CarbonInterval/AddTest.php
+++ b/tests/CarbonInterval/AddTest.php
@@ -30,6 +30,40 @@ class AddTest extends AbstractTestCase
         $this->assertCarbonInterval($ci, 6, 4, 54, 30, 43, 55);
     }
 
+    public function testNamedParameters()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $ci = eval("return \Carbon\CarbonInterval::years(years: 3)->addYears(years: 4);");
+        $this->assertCarbonInterval($ci, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::months(months: 3)->addMonths(months: 4);");
+        $this->assertCarbonInterval($ci, 0, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::weeks(weeks: 3)->addWeeks(weeks: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 7 * 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::days(days: 3)->addDays(days: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::hours(hours: 3)->addHours(hours: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 0, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::minutes(minutes: 3)->addMinutes(minutes: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 0, 0, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::seconds(seconds: 3)->addSeconds(seconds: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 0, 0, 0, 7);
+
+        $ci = eval("return \Carbon\CarbonInterval::milliseconds(milliseconds: 3)->addMilliseconds(milliseconds: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 0, 0, 0, 0, 7000);
+
+        $ci = eval("return \Carbon\CarbonInterval::microseconds(microseconds: 3)->addMicroseconds(microseconds: 4);");
+        $this->assertCarbonInterval($ci, 0, 0, 0, 0, 0, 0, 7);
+    }
+
     public function testAddWithDiffDateInterval()
     {
         $diff = Carbon::now()->diff(Carbon::now()->addWeeks(3));
diff --git a/tests/CarbonPeriod/AliasTest.php b/tests/CarbonPeriod/AliasTest.php
index ceef4dda..37f19df1 100644
--- a/tests/CarbonPeriod/AliasTest.php
+++ b/tests/CarbonPeriod/AliasTest.php
@@ -38,6 +38,37 @@ class AliasTest extends AbstractTestCase
         $this->assertSame(CarbonPeriod::EXCLUDE_START_DATE, $period->getOptions());
     }
 
+    public function testSetStartDateWithNamedParameters()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $date = '2017-09-13 12:30:45';
+        $period = eval('return \Carbon\CarbonPeriod::start(date: $date, inclusive: false);');
+        $this->assertEquals(Carbon::parse($date), $period->getStartDate());
+        $this->assertEquals(Carbon::parse($date), $period->start);
+        $this->assertSame(CarbonPeriod::EXCLUDE_START_DATE, $period->getOptions());
+
+        $period = eval('return \Carbon\CarbonPeriod::start(date: $date);');
+        $this->assertEquals(Carbon::parse($date), $period->getStartDate());
+        $this->assertEquals(Carbon::parse($date), $period->start);
+        $this->assertEmpty($period->getOptions());
+
+        $date = '2014-10-12 15:42:34';
+        eval('$period->since(date: $date, inclusive: true);');
+        $this->assertEquals(Carbon::parse($date), $period->getStartDate());
+        $this->assertEmpty($period->getOptions());
+
+        eval('$period->sinceNow(inclusive: false);');
+        $this->assertEquals(Carbon::now(), $period->getStartDate());
+        $this->assertSame(CarbonPeriod::EXCLUDE_START_DATE, $period->getOptions());
+
+        $period = CarbonPeriod::sinceNow();
+        $this->assertEquals(Carbon::now(), $period->getStartDate());
+        $this->assertEmpty($period->getOptions());
+    }
+
     public function testSetEndDate()
     {
         $period = CarbonPeriod::end($date = '2017-09-13 12:30:45', false);
@@ -57,6 +88,28 @@ class AliasTest extends AbstractTestCase
         $this->assertNull($period->getEndDate());
     }
 
+    public function testSetEndDateWithNamedParameters()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $date = '2017-09-13 12:30:45';
+        $period = eval('return \Carbon\CarbonPeriod::end(date: $date, inclusive: false);');
+        $this->assertEquals(Carbon::parse($date), $period->getEndDate());
+        $this->assertEquals(Carbon::parse($date), $period->end);
+        $this->assertSame(CarbonPeriod::EXCLUDE_END_DATE, $period->getOptions());
+
+        $date = '2014-10-12 15:42:34';
+        eval('$period->until(date: $date, inclusive: true);');
+        $this->assertEquals(Carbon::parse($date), $period->getEndDate());
+        $this->assertEmpty($period->getOptions());
+
+        eval('$period->untilNow(inclusive: false);');
+        $this->assertEquals(Carbon::now(), $period->getEndDate());
+        $this->assertSame(CarbonPeriod::EXCLUDE_END_DATE, $period->getOptions());
+    }
+
     public function testManageFilters()
     {
         $filter = function () {
@@ -203,4 +256,54 @@ class AliasTest extends AbstractTestCase
 
         CarbonPeriod::days(0);
     }
+
+    public function testNamedParameters()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12');");
+        $this->assertEquals('2022-09-13', $period->getStartDate()->format('Y-m-d'));
+        $this->assertEquals('2022-10-12', $period->getEndDate()->format('Y-m-d'));
+
+        eval('$period->years(years: 5);');
+        $this->assertEquals('5 years', (string) $period->getDateInterval());
+
+        eval('$period->interval(interval: \Carbon\CarbonInterval::year(years: 3));');
+        $this->assertEquals('3 years', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->months(months: 5);");
+        $this->assertEquals('5 months', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->weeks(weeks: 5);");
+        $this->assertEquals('5 weeks', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->days(days: 5);");
+        $this->assertEquals('5 days', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->hours(hours: 5);");
+        $this->assertEquals('5 hours', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->minutes(minutes: 5);");
+        $this->assertEquals('5 minutes', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')->seconds(seconds: 5);");
+        $this->assertEquals('5 seconds', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')
+            ->days(days: 5)
+            ->floorDays(precision: 2);");
+        $this->assertEquals('4 days', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')
+            ->days(days: 5)
+            ->roundDays(precision: 7);");
+        $this->assertEquals('1 week', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\CarbonPeriod::between(start: '2022-09-13', end: '2022-10-12')
+            ->days(days: 5)
+            ->ceilDays(precision: 2);");
+        $this->assertEquals('6 days', (string) $period->getDateInterval());
+    }
 }
diff --git a/tests/CarbonPeriod/CreateTest.php b/tests/CarbonPeriod/CreateTest.php
index 344efe2a..23c6e7a6 100644
--- a/tests/CarbonPeriod/CreateTest.php
+++ b/tests/CarbonPeriod/CreateTest.php
@@ -638,6 +638,23 @@ class CreateTest extends AbstractTestCase
         $this->assertNotSame($period, $period4);
     }
 
+    public function testCreateFromCarbonInstancesNamedParameters()
+    {
+        if (version_compare(PHP_VERSION, '8.0.0-dev', '<')) {
+            $this->markTestSkipped('This tests needs PHP 8 named arguments syntax.');
+        }
+
+        $period = eval("return \Carbon\Carbon::create('2019-01-02')->daysUntil(endDate: '2019-02-05');");
+        $this->assertSame('2019-01-02', $period->getStartDate()->format('Y-m-d'));
+        $this->assertSame('2019-02-05', $period->getEndDate()->format('Y-m-d'));
+        $this->assertSame('1 day', (string) $period->getDateInterval());
+
+        $period = eval("return \Carbon\Carbon::create('2019-01-02')->hoursUntil(endDate: '2019-02-05', factor: 12);");
+        $this->assertSame('2019-01-02', $period->getStartDate()->format('Y-m-d'));
+        $this->assertSame('2019-02-05', $period->getEndDate()->format('Y-m-d'));
+        $this->assertSame('12 hours', (string) $period->getDateInterval());
+    }
+
     public function testCast()
     {
         $period = new class('2012-07-01', CarbonInterval::days(2), '2012-07-07') extends CarbonPeriod {