Skip to content

Commit 426199b

Browse files
committed
fix: cast diffInWeeks to int to avoid PHP 8.1+ deprecation warnings
Add explicit (int) cast before modulo operations on diffInWeeks() to prevent 'Implicit conversion from float to int' deprecation. Includes regression test using set_error_handler() to verify fix.
1 parent a15dcb4 commit 426199b

3 files changed

Lines changed: 132 additions & 6 deletions

File tree

src/Data/WeeklyFrequencyConfig/AbstractWeeklyFrequencyConfig.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function shouldCreateInstance(CarbonInterface $date): bool
6666
return $dayMatches;
6767
}
6868

69-
return $dayMatches && $this->startsOn->diffInWeeks($date) % static::getFrequency() === 0;
69+
return $dayMatches && (int) $this->startsOn->diffInWeeks($date) % static::getFrequency() === 0;
7070
}
7171

7272
public function shouldCreateRecurringInstance(Schedule $schedule, CarbonInterface $date): bool
@@ -90,7 +90,7 @@ public function shouldCreateRecurringInstance(Schedule $schedule, CarbonInterfac
9090
}, $allowedDays);
9191

9292
return in_array($date->dayOfWeek, $allowedDayNumbers) &&
93-
$this->startsOn->diffInWeeks($date) % static::getFrequency() === 0;
93+
(int) $this->startsOn->diffInWeeks($date) % static::getFrequency() === 0;
9494
}
9595

9696
public function getNextRecurrence(CarbonInterface $current): CarbonInterface
@@ -126,7 +126,7 @@ protected function getNextBiWeeklyOccurrence(CarbonInterface $current, array $al
126126
}, $allowedDays);
127127

128128
// Find the next allowed day
129-
while (! in_array($next->dayOfWeek, $allowedDayNumbers) || $this->startsOn->diffInWeeks($next) % static::getFrequency() !== 0) {
129+
while (! in_array($next->dayOfWeek, $allowedDayNumbers) || (int) $this->startsOn->diffInWeeks($next) % static::getFrequency() !== 0) {
130130
$next = $next->addDay();
131131

132132
// Prevent infinite loop

src/Data/WeeklyFrequencyConfig/EveryXWeeksFrequencyConfig.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function shouldCreateInstance(CarbonInterface $date): bool
8989
return $dayMatches;
9090
}
9191

92-
return $dayMatches && $this->startsOn->diffInWeeks($date) % $this->frequencyWeeks === 0;
92+
return $dayMatches && (int) $this->startsOn->diffInWeeks($date) % $this->frequencyWeeks === 0;
9393
}
9494

9595
public function shouldCreateRecurringInstance(Schedule $schedule, CarbonInterface $date): bool
@@ -113,7 +113,7 @@ public function shouldCreateRecurringInstance(Schedule $schedule, CarbonInterfac
113113
}, $allowedDays);
114114

115115
return in_array($date->dayOfWeek, $allowedDayNumbers) &&
116-
$this->startsOn->diffInWeeks($date) % $this->frequencyWeeks === 0;
116+
(int) $this->startsOn->diffInWeeks($date) % $this->frequencyWeeks === 0;
117117
}
118118

119119
public function getNextRecurrence(CarbonInterface $current): CarbonInterface
@@ -143,7 +143,7 @@ public function getNextRecurrence(CarbonInterface $current): CarbonInterface
143143
};
144144
}, $allowedDays);
145145

146-
while (! in_array($next->dayOfWeek, $allowedDayNumbers) || $this->startsOn->diffInWeeks($next) % $this->frequencyWeeks !== 0) {
146+
while (! in_array($next->dayOfWeek, $allowedDayNumbers) || (int) $this->startsOn->diffInWeeks($next) % $this->frequencyWeeks !== 0) {
147147
$next = $next->addDay();
148148

149149
if ($next->diffInDays($current) > $this->frequencyWeeks * 7 * 2) {
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
use Carbon\Carbon;
4+
use Zap\Data\WeeklyFrequencyConfig\BiWeeklyFrequencyConfig;
5+
use Zap\Data\WeeklyFrequencyConfig\EveryXWeeksFrequencyConfig;
6+
7+
/**
8+
* These tests verify that PHP 8.1+ deprecation warnings for implicit float to int
9+
* conversions do not occur when using diffInWeeks() with the modulo operator.
10+
*
11+
* @see https://wiki.php.net/rfc/implicit-float-int-deprecate
12+
* @see https://php.watch/versions/8.1/deprecate-implicit-conversion-incompatible-float-string
13+
*/
14+
describe('PHP 8.1+ Implicit Float to Int Conversion', function () {
15+
16+
it('should NOT emit deprecation warnings with bi-weekly frequency checks', function () {
17+
$deprecationWarnings = [];
18+
19+
set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$deprecationWarnings) {
20+
if ($errno === E_DEPRECATED && str_contains($errstr, 'Implicit conversion from float')) {
21+
$deprecationWarnings[] = [
22+
'message' => $errstr,
23+
'file' => $errfile,
24+
'line' => $errline,
25+
];
26+
}
27+
// Return false to let PHP's internal error handler run as well
28+
return false;
29+
});
30+
31+
try {
32+
$config = new BiWeeklyFrequencyConfig(
33+
days: ['monday', 'wednesday'],
34+
startsOn: Carbon::parse('2025-03-10')
35+
);
36+
37+
// These dates produce non-integer week differences:
38+
// 10 days = 1.4285714285714286 weeks
39+
// 11 days = 1.5714285714285714 weeks
40+
// 15 days = 2.1428571428571428 weeks
41+
// 16 days = 2.2857142857142856 weeks
42+
$testDates = [
43+
Carbon::parse('2025-03-20'),
44+
Carbon::parse('2025-03-21'),
45+
Carbon::parse('2025-03-25'),
46+
Carbon::parse('2025-03-26'),
47+
];
48+
49+
foreach ($testDates as $date) {
50+
$config->shouldCreateInstance($date);
51+
}
52+
} finally {
53+
restore_error_handler();
54+
}
55+
56+
// If this fails, it means implicit float to int warnings are being emitted
57+
expect($deprecationWarnings)->toBeEmpty(
58+
'Detected implicit float to int conversion warnings. Details: ' .
59+
json_encode($deprecationWarnings, JSON_PRETTY_PRINT)
60+
);
61+
});
62+
63+
it('should NOT emit deprecation warnings with every-X-weeks frequency checks', function () {
64+
$deprecationWarnings = [];
65+
66+
set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$deprecationWarnings) {
67+
if ($errno === E_DEPRECATED && str_contains($errstr, 'Implicit conversion from float')) {
68+
$deprecationWarnings[] = [
69+
'message' => $errstr,
70+
'file' => $errfile,
71+
'line' => $errline,
72+
];
73+
}
74+
return false;
75+
});
76+
77+
try {
78+
$config = new EveryXWeeksFrequencyConfig(
79+
frequencyWeeks: 3,
80+
days: ['tuesday', 'thursday'],
81+
startsOn: Carbon::parse('2025-03-10')
82+
);
83+
84+
$testDates = [
85+
Carbon::parse('2025-03-20'), // 10 days = 1.4285714285714286 weeks
86+
Carbon::parse('2025-03-27'), // 17 days = 2.4285714285714284 weeks
87+
Carbon::parse('2025-04-03'), // 24 days = 3.4285714285714284 weeks
88+
];
89+
90+
foreach ($testDates as $date) {
91+
$config->shouldCreateInstance($date);
92+
}
93+
} finally {
94+
restore_error_handler();
95+
}
96+
97+
expect($deprecationWarnings)->toBeEmpty(
98+
'Detected implicit float to int conversion warnings. Details: ' .
99+
json_encode($deprecationWarnings, JSON_PRETTY_PRINT)
100+
);
101+
});
102+
103+
it('should not emit warnings during getNextRecurrence calculations', function () {
104+
$deprecationWarnings = [];
105+
set_error_handler(function ($errno, $errstr) use (&$deprecationWarnings) {
106+
if ($errno === E_DEPRECATED && str_contains($errstr, 'Implicit conversion from float')) {
107+
$deprecationWarnings[] = $errstr;
108+
}
109+
return true;
110+
});
111+
112+
$config = new BiWeeklyFrequencyConfig(
113+
days: ['monday', 'wednesday', 'friday'],
114+
startsOn: Carbon::parse('2025-03-10')
115+
);
116+
117+
$current = Carbon::parse('2025-03-20');
118+
119+
$next = $config->getNextRecurrence($current);
120+
121+
restore_error_handler();
122+
123+
expect($deprecationWarnings)->toBeEmpty();
124+
expect($next)->toBeInstanceOf(Carbon::class);
125+
});
126+
});

0 commit comments

Comments
 (0)