[Web] Some minor fixes and improvements for PHP 8

This commit is contained in:
andryyy
2021-08-08 16:06:55 +02:00
parent eec75690e0
commit cf8fdae277
138 changed files with 2398 additions and 2342 deletions

View File

@@ -7,30 +7,24 @@
"time",
"DateTime"
],
"homepage": "http://carbon.nesbot.com",
"support": {
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
},
"homepage": "https://carbon.nesbot.com",
"license": "MIT",
"authors": [
{
"name": "Brian Nesbitt",
"email": "brian@nesbot.com",
"homepage": "http://nesbot.com"
"homepage": "https://markido.com"
},
{
"name": "kylekatarnls",
"homepage": "http://github.com/kylekatarnls"
"homepage": "https://github.com/kylekatarnls"
}
],
"prefer-stable": true,
"minimum-stability": "dev",
"bin": ["bin/carbon"],
"require": {
"php": "^7.1.8 || ^8.0",
"ext-json": "*",
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0"
},
"require-dev": {
@@ -43,43 +37,14 @@
"phpunit/phpunit": "^7.5.20 || ^8.5.14",
"squizlabs/php_codesniffer": "^3.4"
},
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"autoload-dev": {
"files": [
"tests/Laravel/ServiceProvider.php"
],
"psr-4": {
"Tests\\": "tests/"
}
},
"config": {
"process-timeout": 0,
"sort-packages": true
},
"scripts": {
"test": [
"@phpunit",
"@style-check"
],
"style-check": [
"@phpcs",
"@phpstan",
"@phpmd"
],
"phpunit": "phpunit --verbose",
"phpcs": "php-cs-fixer fix -v --diff --dry-run",
"phpstan": "phpstan analyse --configuration phpstan.neon",
"phpmd": "phpmd src text /phpmd.xml",
"phpdoc": "php phpdoc.php"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev",
"dev-3.x": "3.x-dev"
"dev-3.x": "3.x-dev",
"dev-master": "2.x-dev"
},
"laravel": {
"providers": [
@@ -91,5 +56,43 @@
"extension.neon"
]
}
},
"autoload": {
"psr-4": {
"Carbon\\": "src/Carbon/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
},
"files": [
"tests/Laravel/ServiceProvider.php"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"bin": [
"bin/carbon"
],
"scripts": {
"phpcs": "php-cs-fixer fix -v --diff --dry-run",
"phpdoc": "php phpdoc.php",
"phpmd": "phpmd src text /phpmd.xml",
"phpstan": "phpstan analyse --configuration phpstan.neon",
"phpunit": "phpunit --verbose",
"style-check": [
"@phpcs",
"@phpstan",
"@phpmd"
],
"test": [
"@phpunit",
"@style-check"
]
},
"support": {
"issues": "https://github.com/briannesbitt/Carbon/issues",
"source": "https://github.com/briannesbitt/Carbon"
}
}

View File

@@ -1,154 +0,0 @@
# Contributing to Carbon
## Issue Contributions
Please report any security issue using [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
Please don't disclose security bugs publicly until they have been handled by us.
For any other bug or issue, please click this link and follow the template:
[Create new issue](https://github.com/briannesbitt/Carbon/issues/new)
You may think this template does not apply to your case but please think again. A long description will never be as
clear as a code chunk with the output you expect from it (for either bug report or new features).
## Code Contributions
### Where to begin
We use the label **good first issue** to tag issues that could be a good fit for new contributors, see if there are such issues now following this link:
https://github.com/briannesbitt/Carbon/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
Else, check the roadmap to see what we plan to do in next releases:
https://github.com/briannesbitt/Carbon/issues/1681
### Develop locally, then submit changes
Fork the [GitHub project](https://github.com/briannesbitt/Carbon) and download it locally:
```shell
git clone https://github.com/<username>/Carbon.git
cd Carbon
git remote add upstream https://github.com/briannesbitt/Carbon.git
```
Replace `<username>` with your GitHub username.
Then, you can work on the master or create a specific branch for your development:
```shell
git checkout -b my-feature-branch -t origin/master
```
You can now edit the "Carbon" directory contents.
Before committing, please set your name and your e-mail (use the same e-mail address as in your GitHub account):
```shell
git config --global user.name "Your Name"
git config --global user.email "your.email.address@example.com"
```
The ```--global``` argument will apply this setting for all your git repositories, remove it to set only your Carbon
fork with those settings.
Now you can commit your modifications as you usually do with git:
```shell
git add --all
git commit -m "The commit message log"
```
If your patch fixes an open issue, please insert ```#``` immediately followed by the issue number:
```shell
git commit -m "#21 Fix this or that"
```
Use git rebase (not git merge) to sync your work from time to time:
```shell
git fetch origin
git rebase origin/master
```
Please add some tests for bug fixes and features (so it will ensure next developments will not break your code),
then check all is right with phpunit:
Install PHP if you haven't yet, then install composer:
https://getcomposer.org/download/
Update dependencies:
```
./composer.phar update
```
Or if you installed composer globally:
```
composer update
```
Then call phpunit:
```
./vendor/bin/phpunit
```
Make sure all tests succeed before submitting your pull-request, else we will not be able to merge it.
Push your work on your remote GitHub fork with:
```
git push origin my-feature-branch
```
Go to https://github.com/yourusername/Carbon and select your feature branch. Click the 'Pull Request' button and fill
out the form.
We will review it within a few days. And we thank you in advance for your help.
## Versioning
### Note about Semantic Versioning and breaking changes
As a developer, you must understand every change is a breaking change. What is a bug for someone
is expected in someone else's workflow. The consequence of a change strongly depends on the usage.
[Semantic Versioning](https://semver.org/) relies to public API. In PHP, the public API of a class is its public
methods. However, if you extend a class, you can access protected methods, then if you use reflexion, you can
access private methods. So anything can become a public API if you force it to be. That doesn't mean we should handle
any possible usage, else we would have to publish a major release for each change and it would no longer make sense.
So before any complain about a breaking change, be warned, we do not guarantee a strict Semantic Versioning as you
may expect, we're following a pragmatic interpretation of Semantic Versioning that allows the software to evolve in a
reliable way with reasonable maintenance effort.
Concretely, we consider a change as breaking if it makes fail one of our unit test. We will do our best to avoid
incompatibilities with libraries that extends Carbon classes (such as Laravel that is continuously tested thanks to
Travis CI, [see the compatibility matrix](https://github.com/kylekatarnls/carbon-laravel/tree/master#carbon-1-dev-version-1next)).
If you're the owner of a library that strongly depends on Carbon, we recommend you to run unit tests daily requiring
`"nesbot/carbon": "dev-master"` (for `^2`) or `"nesbot/carbon": "dev-version-1.next"` (for `^1`), this way you can
detect incompatibilities earlier and report it to us before we tag a release. We'll pay attention and try to fix it to
make update to next minor releases as soft as possible.
We reserve the right to publish emergency patches within 24 hours after a release if a tag that does not respect
this pattern would have been released despite our vigilance. In this very rare and particular case, we would mark the
tag as broken on GitHub and backward compatibility would be based on previous stable tag.
Last, you must understand that Carbon extends PHP natives classes, that means Carbon can be impacted by any change
that occurs in the date/time API of PHP. We watch new PHP versions and handle those changes as quickly as possible
when detected, but as PHP does not follow the semantic versioning pattern, it basically means any releases (including
patches) can have unexpected consequences on Carbon methods results.
### Long term support
To benefit the better support, require Carbon using major version range (`^1` or `^2`). By requiring `1.26.*`,
`~1.26.0` or limited range such as `>=1.20 <1.33`, you fall to low priority support (only security and critical issues
will be fixed), our prior support goes to next minor releases of each major version. It applies to bug fixes and
low-cost features. Other new features will only be added in the last stable release. At the opposite, we recommend you
to restrain to a major number, as there is no compatibility guarantee from a major version to the next. It means
requiring `>=2`, as it allows any newer version, will probably leads to errors on releasing our next major version.
Open milestones can be patched if a minor bug is detected while if you're on a closed milestone, we'll more likely
ask you to update first to an open one. See currently open milestones:
https://github.com/briannesbitt/Carbon/milestones

View File

@@ -1,46 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Mess detection rules for Carbon"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
Mess detection rules for Carbon
</description>
<rule ref="rulesets/codesize.xml">
<exclude name="CyclomaticComplexity" />
<exclude name="NPathComplexity" />
<exclude name="ExcessiveMethodLength" />
<exclude name="ExcessiveClassLength" />
<exclude name="ExcessivePublicCount" />
<exclude name="TooManyMethods" />
<exclude name="TooManyPublicMethods" />
<exclude name="ExcessiveClassComplexity" />
</rule>
<rule ref="rulesets/cleancode.xml">
<exclude name="BooleanArgumentFlag" />
<exclude name="StaticAccess" />
<exclude name="IfStatementAssignment" />
<exclude name="UndefinedVariable" />
<exclude name="ErrorControlOperator" />
</rule>
<rule ref="rulesets/controversial.xml" />
<rule ref="rulesets/design.xml">
<exclude name="EvalExpression" />
<exclude name="CouplingBetweenObjects" />
<exclude name="CountInLoopExpression" />
</rule>
<rule ref="rulesets/design.xml/CouplingBetweenObjects">
<properties>
<property name="maximum" value="25" />
</properties>
</rule>
<rule ref="rulesets/naming.xml/ShortVariable">
<properties>
<property name="exceptions" value="ci,id,to,tz" />
</properties>
</rule>
<rule ref="rulesets/unusedcode.xml" />
</ruleset>

View File

@@ -8,7 +8,7 @@
[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-44CC11.svg?longCache=true&style=flat-square)](https://github.com/phpstan/phpstan)
[![Tidelift](https://tidelift.com/badges/github/briannesbitt/Carbon)](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme)
An international PHP extension for DateTime. [http://carbon.nesbot.com](http://carbon.nesbot.com)
An international PHP extension for DateTime. [https://carbon.nesbot.com](https://carbon.nesbot.com)
```php
<?php
@@ -84,7 +84,7 @@ printf("Now: %s", Carbon::now());
### Without Composer
Why are you not using [composer](http://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need.
Why are you not using [composer](https://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need.
```php
<?php
@@ -97,7 +97,7 @@ printf("Now: %s", Carbon::now());
## Docs
[http://carbon.nesbot.com/docs](http://carbon.nesbot.com/docs)
[https://carbon.nesbot.com/docs](https://carbon.nesbot.com/docs)
## Security contact information
@@ -122,7 +122,7 @@ This project exists thanks to all the people who contribute.
Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
<a href="https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme" target="_blank"><img src="https://carbon.nesbot.com/tidelift-brand.png" width="256" height="64"></a>
<a href="https://onlinecasinohex.ca/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/0/avatar.svg" width="192" height="64"></a>
<a href="https://onlinecasinohex.ca/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon" target="_blank"><img src="https://images.opencollective.com/hexcasinoca/2da3af2/logo/256.png" width="85" height="64"></a>
<a href="https://opencollective.com/Carbon/sponsor/0/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/Carbon/sponsor/1/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/Carbon/sponsor/2/website" target="_blank"><img src="https://opencollective.com/Carbon/sponsor/2/avatar.svg"></a>

View File

@@ -555,6 +555,11 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface
return 145261681241552;
}
// Remove if https://bugs.php.net/bug.php?id=81107 is fixed
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {
return 1118290769066902787;
}
return PHP_INT_MAX;
}
@@ -567,6 +572,11 @@ class CarbonImmutable extends DateTimeImmutable implements CarbonInterface
return -135908816449551;
}
// Remove if https://bugs.php.net/bug.php?id=81107 is fixed
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {
return -1118290769066898816;
}
return max(PHP_INT_MIN, -9223372036854773760);
}
}

View File

@@ -26,6 +26,7 @@ use DateTimeInterface;
use DateTimeZone;
use JsonSerializable;
use ReflectionException;
use ReturnTypeWillChange;
use Throwable;
/**
@@ -721,6 +722,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public static function __set_state($dump);
/**
@@ -755,6 +757,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function add($unit, $value = 1, $overflow = null);
/**
@@ -830,6 +833,16 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*/
public function average($date = null);
/**
* Clone the current instance if it's mutable.
*
* This method is convenient to ensure you don't mutate the initial object
* but avoid to make a useless copy of it if it's already immutable.
*
* @return static
*/
public function avoidMutation();
/**
* Determines if the instance is between two others.
*
@@ -1066,6 +1079,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static|false
*/
#[ReturnTypeWillChange]
public static function createFromFormat($format, $time, $tz = null);
/**
@@ -1946,7 +1960,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
/**
* Format the instance with the current locale. You can set the current
* locale using setlocale() http://php.net/setlocale.
* locale using setlocale() https://php.net/setlocale.
*
* @param string $format
*
@@ -2135,6 +2149,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
/**
* {@inheritdoc}
*/
#[ReturnTypeWillChange]
public static function getLastErrors();
/**
@@ -3007,6 +3022,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return array|string
*/
#[ReturnTypeWillChange]
public function jsonSerialize();
/**
@@ -3317,6 +3333,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @see https://php.net/manual/en/datetime.modify.php
*/
#[ReturnTypeWillChange]
public function modify($modify);
/**
@@ -3700,6 +3717,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function setDate($year, $month, $day);
/**
@@ -3764,6 +3782,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function setISODate($year, $week, $day = 1);
/**
@@ -3834,6 +3853,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function setTime($hour, $minute, $second = 0, $microseconds = 0);
/**
@@ -3863,6 +3883,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function setTimestamp($unixTimestamp);
/**
@@ -3872,6 +3893,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function setTimezone($value);
/**
@@ -4213,6 +4235,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @return static
*/
#[ReturnTypeWillChange]
public function sub($unit, $value = 1, $overflow = null);
public function subRealUnit($unit, $value = 1);
@@ -4751,7 +4774,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @param string $key
* @param array $parameters
* @param null $number
* @param string|int|float|null $number
* @param \Symfony\Component\Translation\TranslatorInterface $translator
*
* @return string
@@ -4808,7 +4831,7 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
public static function translateWith(\Symfony\Component\Translation\TranslatorInterface $translator, string $key, array $parameters = [], $number = null): string;
/**
* Format as ->format() do (using date replacements patterns from http://php.net/manual/fr/function.date.php)
* Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)
* but translate words whenever possible (months, day names, etc.) using the current locale.
*
* @param string $format
@@ -4991,6 +5014,8 @@ interface CarbonInterface extends DateTimeInterface, JsonSerializable
*
* @param Closure|static|string|false|null $testNow real or mock Carbon instance
* @param Closure|null $callback
*
* @return mixed
*/
public static function withTestNow($testNow = null, $callback = null);

View File

@@ -353,7 +353,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$spec = $years;
if (!\is_string($spec) || \floatval($years) || preg_match('/^[0-9.]/', $years)) {
if (!\is_string($spec) || (float) $years || preg_match('/^[0-9.]/', $years)) {
$spec = static::PERIOD_PREFIX;
$spec .= $years > 0 ? $years.static::PERIOD_YEARS : '';
@@ -380,7 +380,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
parent::__construct($spec);
if (!\is_null($microseconds)) {
if ($microseconds !== null) {
$this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND;
}
}
@@ -536,7 +536,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
}
$interval = mb_substr($interval, mb_strlen($match[0]));
$instance->$unit += \intval($match[0]);
$instance->$unit += (int) ($match[0]);
continue;
}
@@ -546,7 +546,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
"'$expected'",
$nextCharacter,
'Allowed substitutes for interval formats are '.implode(', ', array_keys(static::$formats))."\n".
'See https://www.php.net/manual/en/function.date.php for their meaning'
'See https://php.net/manual/en/function.date.php for their meaning'
);
}
@@ -679,8 +679,8 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
preg_match_all($pattern, $intervalDefinition, $parts, PREG_SET_ORDER);
while ([$part, $value, $unit] = array_shift($parts)) {
$intValue = \intval($value);
$fraction = \floatval($value) - $intValue;
$intValue = (int) $value;
$fraction = (float) $value - $intValue;
// Fix calculation precision
switch (round($fraction, 6)) {
@@ -964,7 +964,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
*
* @return static
*
* @link http://php.net/manual/en/dateinterval.createfromdatestring.php
* @link https://php.net/manual/en/dateinterval.createfromdatestring.php
*/
#[ReturnTypeWillChange]
public static function createFromDateString($time)
@@ -996,7 +996,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
*/
public function get($name)
{
if (substr($name, 0, 5) === 'total') {
if (str_starts_with($name, 'total')) {
return $this->total(substr($name, 5));
}
@@ -1360,7 +1360,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$minimumUnit = 's';
extract($this->getForHumansInitialVariables($syntax, $short));
if (\is_null($syntax)) {
if ($syntax === null) {
$syntax = CarbonInterface::DIFF_ABSOLUTE;
}
@@ -1368,7 +1368,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
$parts = INF;
}
if (\is_null($options)) {
if ($options === null) {
$options = static::getHumanDiffOptions();
}
@@ -1860,7 +1860,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
[$value, $unit] = [$unit, $value];
}
return $this->add($unit, -\floatval($value));
return $this->add($unit, -(float) $value);
}
/**
@@ -2104,7 +2104,7 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
public static function compareDateIntervals(DateInterval $first, DateInterval $second)
{
$current = Carbon::now();
$passed = $current->copy()->add($second);
$passed = $current->avoidMutation()->add($second);
$current->add($first);
if ($current < $passed) {
@@ -2242,12 +2242,12 @@ class CarbonInterval extends DateInterval implements CarbonConverterInterface
'years' => $this->years,
'months' => $this->months,
'weeks' => (int) ($this->d / $daysPerWeek),
'dayz' => (int) ($this->d % $daysPerWeek),
'dayz' => $this->d % $daysPerWeek,
'hours' => $this->hours,
'minutes' => $this->minutes,
'seconds' => $this->seconds,
'milliseconds' => (int) ($this->microseconds / Carbon::MICROSECONDS_PER_MILLISECOND),
'microseconds' => (int) ($this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND),
'microseconds' => $this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND,
];
if (isset($factors['dayz']) && $factors['dayz'][0] !== 'weeks') {

View File

@@ -32,6 +32,7 @@ use InvalidArgumentException;
use Iterator;
use JsonSerializable;
use ReflectionException;
use ReturnTypeWillChange;
use RuntimeException;
/**
@@ -875,7 +876,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/
public function setOptions($options)
{
if (!\is_int($options) && !\is_null($options)) {
if (!\is_int($options) && $options !== null) {
throw new InvalidPeriodParameterException('Invalid options.');
}
@@ -962,7 +963,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/
public function getStartDate(string $rounding = null)
{
$date = $this->startDate->copy();
$date = $this->startDate->avoidMutation();
return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;
}
@@ -980,7 +981,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
return null;
}
$date = $this->endDate->copy();
$date = $this->endDate->avoidMutation();
return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;
}
@@ -1220,7 +1221,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/
public function setRecurrences($recurrences)
{
if (!is_numeric($recurrences) && !\is_null($recurrences) || $recurrences < 0) {
if (!is_numeric($recurrences) && $recurrences !== null || $recurrences < 0) {
throw new InvalidPeriodParameterException('Invalid number of recurrences.');
}
@@ -1276,7 +1277,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/
public function setEndDate($date, $inclusive = null)
{
if (!\is_null($date) && !$date = ([$this->dateClass, 'make'])($date)) {
if ($date !== null && !$date = ([$this->dateClass, 'make'])($date)) {
throw new InvalidPeriodDateException('Invalid end date.');
}
@@ -1523,7 +1524,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
{
$state = [
$this->key,
$this->current ? $this->current->copy() : null,
$this->current ? $this->current->avoidMutation() : null,
$this->validationResult,
];
@@ -1722,7 +1723,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
$date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd();
if ($date && $rounding) {
$date = $date->copy()->round($this->getDateInterval(), $rounding);
$date = $date->avoidMutation()->round($this->getDateInterval(), $rounding);
}
return $date;
@@ -1743,13 +1744,13 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
if ($this->recurrences === INF) {
$start = $this->getStartDate();
return $start < $start->copy()->add($this->getDateInterval())
return $start < $start->avoidMutation()->add($this->getDateInterval())
? CarbonImmutable::endOfTime()
: CarbonImmutable::startOfTime();
}
if ($this->filters === [[static::RECURRENCES_FILTER, null]]) {
return $this->getStartDate()->copy()->add(
return $this->getStartDate()->avoidMutation()->add(
$this->getDateInterval()->times(
$this->recurrences - ($this->isStartExcluded() ? 0 : 1)
)
@@ -1795,13 +1796,8 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
$range = static::create($range);
}
$thisDates = [$this->getStartDate(), $this->calculateEnd()];
sort($thisDates);
[$start, $end] = $thisDates;
$rangeDates = [$range->getStartDate(), $range->calculateEnd()];
sort($rangeDates);
[$rangeStart, $rangeEnd] = $rangeDates;
[$start, $end] = $this->orderCouple($this->getStartDate(), $this->calculateEnd());
[$rangeStart, $rangeEnd] = $this->orderCouple($range->getStartDate(), $range->calculateEnd());
return $end > $rangeStart && $rangeEnd > $start;
}
@@ -2168,6 +2164,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*
* @return CarbonInterface[]
*/
#[ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->toArray();
@@ -2283,7 +2280,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
*/
protected function isCarbonPredicateMethod($callable)
{
return \is_string($callable) && substr($callable, 0, 2) === 'is' &&
return \is_string($callable) && str_starts_with($callable, 'is') &&
(method_exists($this->dateClass, $callable) || ([$this->dateClass, 'hasMacro'])($callable));
}
@@ -2384,7 +2381,7 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
foreach ($this->filters as $tuple) {
$result = \call_user_func(
$tuple[0],
$current->copy(),
$current->avoidMutation(),
$this->key,
$this
);
@@ -2493,4 +2490,9 @@ class CarbonPeriod implements Iterator, Countable, JsonSerializable
? static::instance($period)
: static::create($period, ...$arguments);
}
private function orderCouple($first, $second): array
{
return $first > $second ? [$second, $first] : [$first, $second];
}
}

View File

@@ -33,7 +33,7 @@ class CarbonTimeZone extends DateTimeZone
protected static function getDateTimeZoneNameFromMixed($timezone)
{
if (\is_null($timezone)) {
if ($timezone === null) {
return date_default_timezone_get();
}

View File

@@ -37,7 +37,7 @@ trait CarbonTypeConverter
return $type;
}
if (strpos($type, '(') !== false) {
if (str_contains($type, '(')) {
return preg_replace('/\(\d+\)/', "($precision)", $type);
}
@@ -95,7 +95,7 @@ trait CarbonTypeConverter
return $value;
}
if ($value instanceof DateTimeInterface || $value instanceof CarbonInterface) {
if ($value instanceof DateTimeInterface) {
return $value->format('Y-m-d H:i:s.u');
}

View File

@@ -215,7 +215,7 @@ use ReflectionMethod;
* You should rather use the ->settings() method.
* Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
* are available for quarters, years, decade, centuries, millennia (singular and plural forms).
* @method Carbon withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* @method mixed withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* Using setTestNow to set the date, executing the callback, then
* clearing the test instance.
* /!\ Use this method for unit tests only.
@@ -229,7 +229,7 @@ class Factory
protected $settings = [];
public function __construct(array $settings = [], string $className = null)
public function __construct(array $settings = [], ?string $className = null)
{
if ($className) {
$this->className = $className;

View File

@@ -214,7 +214,7 @@ use Closure;
* You should rather use the ->settings() method.
* Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
* are available for quarters, years, decade, centuries, millennia (singular and plural forms).
* @method CarbonImmutable withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* @method mixed withTestNow($testNow = null, $callback = null) Temporarily sets a static date to be used within the callback.
* Using setTestNow to set the date, executing the callback, then
* clearing the test instance.
* /!\ Use this method for unit tests only.

View File

@@ -11,7 +11,7 @@
// @codeCoverageIgnoreStart
if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) {
\Symfony\Component\Translation\PluralizationRules::set(function ($number) {
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
}, 'be');
}
// @codeCoverageIgnoreEnd

View File

@@ -11,7 +11,7 @@
/*
* Authors:
* - Ankur Group, http://www.ankurbangla.org, http://www.bengalinux.org Taneem Ahmed, Jamil Ahmed taneem@bengalinux.org, jamil@bengalinux.org
* - Ankur Group, Taneem Ahmed, Jamil Ahmed
*/
return array_replace_recursive(require __DIR__.'/bn.php', [
'formats' => [

View File

@@ -41,7 +41,7 @@ return [
's' => ':count seg.',
'ago' => 'hai :time',
'from_now' => function ($time) {
if (substr($time, 0, 2) === 'un') {
if (str_starts_with($time, 'un')) {
return "n$time";
}

View File

@@ -169,8 +169,8 @@ return [
return $number.'-ე';
},
'months' => ['იანვარ', 'თებერვალ', 'მარტ', 'აპრილი', 'მაის', 'ივნის', 'ივლის', 'აგვისტ', 'სექტემბერ', 'ოქტომბერ', 'ნოემბერ', 'დეკემბერ'],
'months_standalone' => ['იანვარ', 'თებერვალ', 'მარტ', 'აპრილ', 'მაის', 'ივნის', 'ივლის', 'აგვისტო', 'სექტემბერ', 'ოქტომბერ', 'ნოემბერ', 'დეკემბერ'],
'months' => ['იანვარ', 'თებერვალ', 'მარტ', 'აპრილი', 'მაის', 'ივნის', 'ივლის', 'აგვისტ', 'სექტემბერ', 'ოქტომბერ', 'ნოემბერ', 'დეკემბერ'],
'months_standalone' => ['იანვარ', 'თებერვალ', 'მარტ', 'აპრილ', 'მაის', 'ივნის', 'ივლის', 'აგვისტო', 'სექტემბერ', 'ოქტომბერ', 'ნოემბერ', 'დეკემბერ'],
'months_short' => ['იან', 'თებ', 'მარ', 'აპრ', 'მაი', 'ივნ', 'ივლ', 'აგვ', 'სექ', 'ოქტ', 'ნოე', 'დეკ'],
'months_regexp' => '/(D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|L{2,4}|l{2,4})/',
'weekdays' => ['კვირას', 'ორშაბათს', 'სამშაბათს', 'ოთხშაბათს', 'ხუთშაბათს', 'პარასკევს', 'შაბათს'],

View File

@@ -69,7 +69,7 @@ return [
'diff_after_tomorrow' => 'overmorgen',
'diff_before_yesterday' => 'eergisteren',
'period_recurrences' => ':count keer',
'period_interval' => function ($interval) {
'period_interval' => function (string $interval = '') {
/** @var string $output */
$output = preg_replace('/^(een|één|1)\s+/', '', $interval);

View File

@@ -82,7 +82,7 @@ return [
'weekdays' => ['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'],
'weekdays_short' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],
'weekdays_min' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],
'ordinal' => function ($number, $period) {
'ordinal' => function ($number, string $period = '') {
$ordinal = [1 => 'èr', 2 => 'nd'][(int) $number] ?? 'en';
// feminine for year, week, hour, minute, second

View File

@@ -29,7 +29,7 @@
return [
'year' => ':count rok|:count lata|:count lat',
'a_year' => 'rok|:count lata|:count lat',
'y' => ':count r|:count l',
'y' => ':count r|:count l|:count l',
'month' => ':count miesiąc|:count miesiące|:count miesięcy',
'a_month' => 'miesiąc|:count miesiące|:count miesięcy',
'm' => ':count mies.',

View File

@@ -11,7 +11,7 @@
// @codeCoverageIgnoreStart
if (class_exists('Symfony\\Component\\Translation\\PluralizationRules')) {
\Symfony\Component\Translation\PluralizationRules::set(function ($number) {
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
}, 'sh');
}
// @codeCoverageIgnoreEnd

View File

@@ -11,7 +11,7 @@
/*
* Authors:
* - ubuntu Myanmar LoCo Team http://www.ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com
* - ubuntu Myanmar LoCo Team https://ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com
*/
return array_replace_recursive(require __DIR__.'/en.php', [
'formats' => [

View File

@@ -11,6 +11,7 @@
namespace Carbon;
use JsonSerializable;
use ReturnTypeWillChange;
class Language implements JsonSerializable
{
@@ -332,6 +333,7 @@ class Language implements JsonSerializable
*
* @return string
*/
#[ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->getIsoDescription();

View File

@@ -622,7 +622,7 @@ trait Comparison
if (!isset($units[$unit])) {
if (isset($this->$unit)) {
return $this->$unit === $this->resolveCarbon($date)->$unit;
return $this->resolveCarbon($date)->$unit === $this->$unit;
}
if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {
@@ -949,7 +949,7 @@ trait Comparison
$tester = trim($tester);
if (preg_match('/^\d+$/', $tester)) {
return $this->year === \intval($tester);
return $this->year === (int) $tester;
}
if (preg_match('/^\d{3,}-\d{1,2}$/', $tester)) {
@@ -964,9 +964,9 @@ trait Comparison
/* @var CarbonInterface $max */
$median = static::parse('5555-06-15 12:30:30.555555')->modify($modifier);
$current = $this->copy();
$current = $this->avoidMutation();
/* @var CarbonInterface $other */
$other = $this->copy()->modify($modifier);
$other = $this->avoidMutation()->modify($modifier);
if ($current->eq($other)) {
return true;
@@ -1001,7 +1001,7 @@ trait Comparison
];
foreach ($units as $unit => [$minimum, $startUnit]) {
if ($median->$unit === $minimum) {
if ($minimum === $median->$unit) {
$current = $current->startOf($startUnit);
break;

View File

@@ -38,7 +38,7 @@ trait Converter
*
* @var string|Closure|null
*/
protected static $toStringFormat = null;
protected static $toStringFormat;
/**
* Reset the format used to the default when type juggling a Carbon instance to a string
@@ -324,7 +324,9 @@ trait Converter
*/
public function toIso8601ZuluString($unitPrecision = 'second')
{
return $this->copy()->utc()->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z');
return $this->avoidMutation()
->utc()
->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z');
}
/**
@@ -452,7 +454,7 @@ trait Converter
*/
public function toRfc7231String()
{
return $this->copy()
return $this->avoidMutation()
->setTimezone('GMT')
->rawFormat(\defined('static::RFC7231_FORMAT') ? static::RFC7231_FORMAT : CarbonInterface::RFC7231_FORMAT);
}
@@ -512,7 +514,7 @@ trait Converter
*/
public function toString()
{
return $this->copy()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
return $this->avoidMutation()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
}
/**
@@ -537,7 +539,7 @@ trait Converter
$yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY';
$tzFormat = $keepOffset ? 'Z' : '[Z]';
$date = $keepOffset ? $this : $this->copy()->utc();
$date = $keepOffset ? $this : $this->avoidMutation()->utc();
return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat");
}

View File

@@ -77,7 +77,7 @@ trait Creator
}
// Work-around for PHP bug https://bugs.php.net/bug.php?id=67127
if (strpos((string) .1, '.') === false) {
if (!str_contains((string) .1, '.')) {
$locale = setlocale(LC_NUMERIC, '0');
setlocale(LC_NUMERIC, 'C');
}
@@ -592,7 +592,7 @@ trait Creator
// @codeCoverageIgnoreEnd
if ($originalTz === null) {
return parent::createFromFormat($format, "$time");
return parent::createFromFormat($format, (string) $time);
}
$tz = \is_int($originalTz)
@@ -605,7 +605,7 @@ trait Creator
return false;
}
return parent::createFromFormat($format, "$time", $tz);
return parent::createFromFormat($format, (string) $time, $tz);
}
/**

View File

@@ -27,6 +27,7 @@ use Closure;
use DateInterval;
use DatePeriod;
use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use InvalidArgumentException;
@@ -630,7 +631,7 @@ trait Date
*
* @return CarbonTimeZone
*
* @link http://php.net/manual/en/datetime.gettimezone.php
* @link https://php.net/manual/en/datetime.gettimezone.php
*/
#[ReturnTypeWillChange]
public function getTimezone()
@@ -683,6 +684,23 @@ trait Date
return clone $this;
}
/**
* Clone the current instance if it's mutable.
*
* This method is convenient to ensure you don't mutate the initial object
* but avoid to make a useless copy of it if it's already immutable.
*
* @return static
*/
public function avoidMutation(): self
{
if ($this instanceof DateTimeImmutable) {
return $this;
}
return clone $this;
}
/**
* Returns a present instance in the same timezone.
*
@@ -774,7 +792,7 @@ trait Date
public function carbonize($date = null)
{
if ($date instanceof DateInterval) {
return $this->copy()->add($date);
return $this->avoidMutation()->add($date);
}
if ($date instanceof DatePeriod || $date instanceof CarbonPeriod) {
@@ -872,7 +890,7 @@ trait Date
switch (true) {
case isset($formats[$name]):
$format = $formats[$name];
$method = substr($format, 0, 1) === '%' ? 'formatLocalized' : 'rawFormat';
$method = str_starts_with($format, '%') ? 'formatLocalized' : 'rawFormat';
$value = $this->$method($format);
return is_numeric($value) ? (int) $value : $value;
@@ -927,11 +945,11 @@ trait Date
// @property-read int 51 through 53
case $name === 'weeksInYear':
return (int) $this->weeksInYear();
return $this->weeksInYear();
// @property-read int 51 through 53
case $name === 'isoWeeksInYear':
return (int) $this->isoWeeksInYear();
return $this->isoWeeksInYear();
// @property-read int 1 through 5
case $name === 'weekOfMonth':
@@ -939,7 +957,7 @@ trait Date
// @property-read int 1 through 5
case $name === 'weekNumberInMonth':
return (int) ceil(($this->day + $this->copy()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK);
return (int) ceil(($this->day + $this->avoidMutation()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK);
// @property-read int 0 through 6
case $name === 'firstWeekDay':
@@ -951,7 +969,7 @@ trait Date
// @property int 1 through 366
case $name === 'dayOfYear':
return 1 + \intval($this->rawFormat('z'));
return 1 + (int) ($this->rawFormat('z'));
// @property-read int 365 or 366
case $name === 'daysInYear':
@@ -1013,7 +1031,7 @@ trait Date
// @property-read bool checks if the timezone is local, true if local, false otherwise
case $name === 'local':
return $this->getOffset() === $this->copy()->setTimezone(date_default_timezone_get())->getOffset();
return $this->getOffset() === $this->avoidMutation()->setTimezone(date_default_timezone_get())->getOffset();
// @property-read bool checks if the timezone is UTC, true if UTC, false otherwise
case $name === 'utc':
@@ -1114,7 +1132,7 @@ trait Date
case 'microseconds':
case 'microsecond':
case 'micro':
if (substr($name, 0, 5) === 'milli') {
if (str_starts_with($name, 'milli')) {
$value *= 1000;
}
@@ -1309,7 +1327,7 @@ trait Date
{
$dayOfYear = $this->dayOfYear;
return \is_null($value) ? $dayOfYear : $this->addDays($value - $dayOfYear);
return $value === null ? $dayOfYear : $this->addDays($value - $dayOfYear);
}
/**
@@ -1321,9 +1339,9 @@ trait Date
*/
public function weekday($value = null)
{
$dayOfWeek = ($this->dayOfWeek + 7 - \intval($this->getTranslationMessage('first_day_of_week') ?? 0)) % 7;
$dayOfWeek = ($this->dayOfWeek + 7 - (int) ($this->getTranslationMessage('first_day_of_week') ?? 0)) % 7;
return \is_null($value) ? $dayOfWeek : $this->addDays($value - $dayOfWeek);
return $value === null ? $dayOfWeek : $this->addDays($value - $dayOfWeek);
}
/**
@@ -1337,7 +1355,7 @@ trait Date
{
$dayOfWeekIso = $this->dayOfWeekIso;
return \is_null($value) ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso);
return $value === null ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso);
}
/**
@@ -1352,11 +1370,11 @@ trait Date
public function setUnitNoOverflow($valueUnit, $value, $overflowUnit)
{
try {
$original = $this->copy();
$original = $this->avoidMutation();
/** @var static $date */
$date = $this->$valueUnit($value);
$end = $original->copy()->endOf($overflowUnit);
$start = $original->copy()->startOf($overflowUnit);
$end = $original->avoidMutation()->endOf($overflowUnit);
$start = $original->avoidMutation()->startOf($overflowUnit);
if ($date < $start) {
$date = $date->setDateTimeFrom($start);
} elseif ($date > $end) {
@@ -1509,7 +1527,7 @@ trait Date
*/
public function setTimeFromTimeString($time)
{
if (strpos($time, ':') === false) {
if (!str_contains($time, ':')) {
$time .= ':0';
}
@@ -1791,7 +1809,7 @@ trait Date
/**
* Format the instance with the current locale. You can set the current
* locale using setlocale() http://php.net/setlocale.
* locale using setlocale() https://php.net/setlocale.
*
* @param string $format
*
@@ -1900,7 +1918,7 @@ trait Date
's' => 'second',
'ss' => ['getPaddedUnit', ['second']],
'S' => function (CarbonInterface $date) {
return \strval((string) floor($date->micro / 100000));
return (string) floor($date->micro / 100000);
},
'SS' => function (CarbonInterface $date) {
return str_pad((string) floor($date->micro / 10000), 2, '0', STR_PAD_LEFT);
@@ -1999,15 +2017,15 @@ trait Date
*
* @return string
*/
public function ordinal(string $key, string $period = null): string
public function ordinal(string $key, ?string $period = null): string
{
$number = $this->$key;
$result = $this->translate('ordinal', [
':number' => $number,
':period' => $period,
':period' => (string) $period,
]);
return \strval($result === 'ordinal' ? $number : $result);
return (string) ($result === 'ordinal' ? $number : $result);
}
/**
@@ -2070,7 +2088,7 @@ trait Date
*
* @return string
*/
public function isoFormat(string $format, string $originalFormat = null): string
public function isoFormat(string $format, ?string $originalFormat = null): string
{
$result = '';
$length = mb_strlen($format);
@@ -2149,7 +2167,7 @@ trait Date
}
$format = mb_substr($format, 0, $i).$sequence.mb_substr($format, $i + mb_strlen($code));
$i += mb_strlen("$sequence") - 1;
$i += mb_strlen((string) $sequence) - 1;
$length = mb_strlen($format);
$char = $sequence;
}
@@ -2179,7 +2197,7 @@ trait Date
'S' => function ($date) {
$day = $date->rawFormat('j');
return str_replace("$day", '', $date->isoFormat('Do'));
return str_replace((string) $day, '', $date->isoFormat('Do'));
},
'w' => true,
'z' => true,
@@ -2219,7 +2237,7 @@ trait Date
}
/**
* Format as ->format() do (using date replacements patterns from http://php.net/manual/fr/function.date.php)
* Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)
* but translate words whenever possible (months, day names, etc.) using the current locale.
*
* @param string $format
@@ -2519,7 +2537,7 @@ trait Date
$unit = rtrim($method, 's');
if (substr($unit, 0, 2) === 'is') {
if (str_starts_with($unit, 'is')) {
$word = substr($unit, 2);
if (\in_array($word, static::$days)) {
@@ -2557,7 +2575,7 @@ trait Date
if ($action === 'add' || $action === 'sub') {
$unit = substr($unit, 3);
if (substr($unit, 0, 4) === 'Real') {
if (str_starts_with($unit, 'Real')) {
$unit = static::singularUnit(substr($unit, 4));
return $this->{"${action}RealUnit"}($unit, ...$parameters);
@@ -2599,7 +2617,7 @@ trait Date
}
}
if (substr($unit, 0, 9) === 'isCurrent') {
if (str_starts_with($unit, 'isCurrent')) {
try {
return $this->isCurrentUnit(strtolower(substr($unit, 9)));
} catch (BadComparisonUnitException | BadMethodCallException $exception) {
@@ -2607,7 +2625,7 @@ trait Date
}
}
if (substr($method, -5) === 'Until') {
if (str_ends_with($method, 'Until')) {
try {
$unit = static::singularUnit(substr($method, 0, -5));

View File

@@ -121,7 +121,17 @@ trait Difference
#[ReturnTypeWillChange]
public function diff($date = null, $absolute = false)
{
return parent::diff($this->resolveCarbon($date), (bool) $absolute);
$other = $this->resolveCarbon($date);
// Can be removed if https://github.com/derickr/timelib/pull/110
// is merged
// @codeCoverageIgnoreStart
if (version_compare(PHP_VERSION, '8.1.0-dev', '>=') && $other->tz !== $this->tz) {
$other = $other->avoidMutation()->tz($this->tz);
}
// @codeCoverageIgnoreEnd
return parent::diff($other, (bool) $absolute);
}
/**
@@ -540,14 +550,14 @@ trait Difference
}
$monthsDiff = $start->diffInMonths($end);
/** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addMonths($monthsDiff);
$floorEnd = $start->avoidMutation()->addMonths($monthsDiff);
if ($floorEnd >= $end) {
return $sign * $monthsDiff;
}
/** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
$startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
$startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();
if ($startOfMonthAfterFloorEnd > $end) {
return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth);
@@ -575,14 +585,14 @@ trait Difference
}
$yearsDiff = $start->diffInYears($end);
/** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addYears($yearsDiff);
$floorEnd = $start->avoidMutation()->addYears($yearsDiff);
if ($floorEnd >= $end) {
return $sign * $yearsDiff;
}
/** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
$startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
$startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();
if ($startOfYearAfterFloorEnd > $end) {
return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear);
@@ -641,7 +651,7 @@ trait Difference
public function floatDiffInRealDays($date = null, $absolute = true)
{
$date = $this->resolveUTC($date);
$utc = $this->copy()->utc();
$utc = $this->avoidMutation()->utc();
$hoursDiff = $utc->floatDiffInRealHours($date, $absolute);
return ($hoursDiff < 0 ? -1 : 1) * $utc->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
@@ -679,14 +689,14 @@ trait Difference
}
$monthsDiff = $start->diffInMonths($end);
/** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addMonths($monthsDiff);
$floorEnd = $start->avoidMutation()->addMonths($monthsDiff);
if ($floorEnd >= $end) {
return $sign * $monthsDiff;
}
/** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
$startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
$startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();
if ($startOfMonthAfterFloorEnd > $end) {
return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth);
@@ -714,14 +724,14 @@ trait Difference
}
$yearsDiff = $start->diffInYears($end);
/** @var Carbon|CarbonImmutable $floorEnd */
$floorEnd = $start->copy()->addYears($yearsDiff);
$floorEnd = $start->avoidMutation()->addYears($yearsDiff);
if ($floorEnd >= $end) {
return $sign * $yearsDiff;
}
/** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
$startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
$startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();
if ($startOfYearAfterFloorEnd > $end) {
return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear);
@@ -737,7 +747,7 @@ trait Difference
*/
public function secondsSinceMidnight()
{
return $this->diffInSeconds($this->copy()->startOfDay());
return $this->diffInSeconds($this->avoidMutation()->startOfDay());
}
/**
@@ -747,7 +757,7 @@ trait Difference
*/
public function secondsUntilEndOfDay()
{
return $this->diffInSeconds($this->copy()->endOfDay());
return $this->diffInSeconds($this->avoidMutation()->endOfDay());
}
/**
@@ -1106,9 +1116,9 @@ trait Difference
public function calendar($referenceTime = null, array $formats = [])
{
/** @var CarbonInterface $current */
$current = $this->copy()->startOfDay();
$current = $this->avoidMutation()->startOfDay();
/** @var CarbonInterface $other */
$other = $this->resolveCarbon($referenceTime)->copy()->setTimezone($this->getTimezone())->startOfDay();
$other = $this->resolveCarbon($referenceTime)->avoidMutation()->setTimezone($this->getTimezone())->startOfDay();
$diff = $other->diffInDays($current, false);
$format = $diff < -6 ? 'sameElse' : (
$diff < -1 ? 'lastWeek' : (
@@ -1126,6 +1136,6 @@ trait Difference
$format = $format($current, $other) ?? '';
}
return $this->isoFormat(\strval($format));
return $this->isoFormat((string) $format);
}
}

View File

@@ -64,7 +64,7 @@ trait IntervalStep
$carbonDate = $dateTime instanceof CarbonInterface ? $dateTime : $this->resolveCarbon($dateTime);
if ($this->step) {
return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->copy(), $negated));
return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->avoidMutation(), $negated));
}
if ($negated) {

View File

@@ -168,7 +168,7 @@ trait Localization
*
* @return string
*/
public static function getTranslationMessageWith($translator, string $key, string $locale = null, string $default = null)
public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null)
{
if (!($translator instanceof TranslatorBagInterface && $translator instanceof TranslatorInterface)) {
throw new InvalidTypeException(
@@ -196,7 +196,7 @@ trait Localization
*
* @return string
*/
public function getTranslationMessage(string $key, string $locale = null, string $default = null, $translator = null)
public function getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)
{
return static::getTranslationMessageWith($translator ?: $this->getLocalTranslator(), $key, $locale, $default);
}
@@ -239,12 +239,12 @@ trait Localization
*
* @param string $key
* @param array $parameters
* @param null $number
* @param string|int|float|null $number
* @param \Symfony\Component\Translation\TranslatorInterface $translator
*
* @return string
*/
public function translate(string $key, array $parameters = [], $number = null, TranslatorInterface $translator = null, bool $altNumbers = false): string
public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string
{
$translation = static::translateWith($translator ?: $this->getLocalTranslator(), $key, $parameters, $number);
@@ -302,7 +302,7 @@ trait Localization
return $result;
}
return "$number";
return (string) $number;
}
/**

View File

@@ -224,11 +224,11 @@ trait Modifiers
*/
public function nthOfMonth($nth, $dayOfWeek)
{
$date = $this->copy()->firstOfMonth();
$date = $this->avoidMutation()->firstOfMonth();
$check = $date->rawFormat('Y-m');
$date = $date->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return $date->rawFormat('Y-m') === $check ? $this->modify("$date") : false;
return $date->rawFormat('Y-m') === $check ? $this->modify((string) $date) : false;
}
/**
@@ -274,12 +274,12 @@ trait Modifiers
*/
public function nthOfQuarter($nth, $dayOfWeek)
{
$date = $this->copy()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER);
$date = $this->avoidMutation()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER);
$lastMonth = $date->month;
$year = $date->year;
$date = $date->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify("$date");
return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify((string) $date);
}
/**
@@ -325,9 +325,9 @@ trait Modifiers
*/
public function nthOfYear($nth, $dayOfWeek)
{
$date = $this->copy()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
$date = $this->avoidMutation()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
return $this->year === $date->year ? $this->modify("$date") : false;
return $this->year === $date->year ? $this->modify((string) $date) : false;
}
/**
@@ -454,7 +454,7 @@ trait Modifiers
{
return $this->modify(preg_replace_callback('/^(next|previous|last)\s+(\d{1,2}(h|am|pm|:\d{1,2}(:\d{1,2})?))$/i', function ($match) {
$match[2] = str_replace('h', ':00', $match[2]);
$test = $this->copy()->modify($match[2]);
$test = $this->avoidMutation()->modify($match[2]);
$method = $match[1] === 'next' ? 'lt' : 'gt';
$match[1] = $test->$method($this) ? $match[1].' day' : 'today';

View File

@@ -17,5 +17,5 @@ trait ObjectInitialisation
*
* @var string
*/
protected $constructedObjectId = null;
protected $constructedObjectId;
}

View File

@@ -151,21 +151,21 @@ trait Options
*
* @var string|callable|null
*/
protected static $formatFunction = null;
protected static $formatFunction;
/**
* Function to call instead of createFromFormat.
*
* @var string|callable|null
*/
protected static $createFromFormatFunction = null;
protected static $createFromFormatFunction;
/**
* Function to call instead of parse.
*
* @var string|callable|null
*/
protected static $parseFunction = null;
protected static $parseFunction;
/**
* Indicates if months should be calculated with overflow.
@@ -173,7 +173,7 @@ trait Options
*
* @var bool|null
*/
protected $localMonthsOverflow = null;
protected $localMonthsOverflow;
/**
* Indicates if years should be calculated with overflow.
@@ -181,7 +181,7 @@ trait Options
*
* @var bool|null
*/
protected $localYearsOverflow = null;
protected $localYearsOverflow;
/**
* Indicates if the strict mode is in use.
@@ -189,49 +189,49 @@ trait Options
*
* @var bool|null
*/
protected $localStrictModeEnabled = null;
protected $localStrictModeEnabled;
/**
* Options for diffForHumans and forHumans methods.
*
* @var bool|null
*/
protected $localHumanDiffOptions = null;
protected $localHumanDiffOptions;
/**
* Format to use on string cast.
*
* @var string|null
*/
protected $localToStringFormat = null;
protected $localToStringFormat;
/**
* Format to use on JSON serialization.
*
* @var string|null
*/
protected $localSerializer = null;
protected $localSerializer;
/**
* Instance-specific macros.
*
* @var array|null
*/
protected $localMacros = null;
protected $localMacros;
/**
* Instance-specific generic macros.
*
* @var array|null
*/
protected $localGenericMacros = null;
protected $localGenericMacros;
/**
* Function to call instead of format.
*
* @var string|callable|null
*/
protected $localFormatFunction = null;
protected $localFormatFunction;
/**
* @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
@@ -449,7 +449,7 @@ trait Options
protected function addExtraDebugInfos(&$infos): void
{
if ($this instanceof CarbonInterface || $this instanceof DateTimeInterface) {
if ($this instanceof DateTimeInterface) {
try {
if (!isset($infos['date'])) {
$infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT);

View File

@@ -194,7 +194,10 @@ trait Rounding
*/
public function roundWeek($weekStartsAt = null)
{
return $this->closest($this->copy()->floorWeek($weekStartsAt), $this->copy()->ceilWeek($weekStartsAt));
return $this->closest(
$this->avoidMutation()->floorWeek($weekStartsAt),
$this->avoidMutation()->ceilWeek($weekStartsAt)
);
}
/**
@@ -219,7 +222,7 @@ trait Rounding
public function ceilWeek($weekStartsAt = null)
{
if ($this->isMutable()) {
$startOfWeek = $this->copy()->startOfWeek($weekStartsAt);
$startOfWeek = $this->avoidMutation()->startOfWeek($weekStartsAt);
return $startOfWeek != $this ?
$this->startOfWeek($weekStartsAt)->addWeek() :
@@ -230,6 +233,6 @@ trait Rounding
return $startOfWeek != $this ?
$startOfWeek->addWeek() :
$this->copy();
$this->avoidMutation();
}
}

View File

@@ -12,6 +12,7 @@ namespace Carbon\Traits;
use Carbon\Exceptions\InvalidFormatException;
use ReturnTypeWillChange;
use Throwable;
/**
* Trait Serialization.
@@ -53,7 +54,15 @@ trait Serialization
*
* @var string|null
*/
protected $dumpLocale = null;
protected $dumpLocale;
/**
* Embed date properties to dump in a dedicated variables so it won't overlap native
* DateTime ones.
*
* @var array|null
*/
protected $dumpDateProperties;
/**
* Return a serialized string of the instance.
@@ -76,7 +85,7 @@ trait Serialization
*/
public static function fromSerialized($value)
{
$instance = @unserialize("$value");
$instance = @unserialize((string) $value);
if (!$instance instanceof static) {
throw new InvalidFormatException("Invalid serialized value: $value");
@@ -114,7 +123,7 @@ trait Serialization
*/
public function __sleep()
{
$properties = $this->dumpProperties;
$properties = $this->getSleepProperties();
if ($this->localTranslator ?? null) {
$properties[] = 'dumpLocale';
@@ -131,7 +140,15 @@ trait Serialization
public function __wakeup()
{
if (get_parent_class() && method_exists(parent::class, '__wakeup')) {
parent::__wakeup();
// @codeCoverageIgnoreStart
try {
parent::__wakeup();
} catch (Throwable $exception) {
// FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later.
['date' => $date, 'timezone' => $timezone] = $this->dumpDateProperties;
parent::__construct($date, unserialize($timezone));
}
// @codeCoverageIgnoreEnd
}
$this->constructedObjectId = spl_object_hash($this);
@@ -149,6 +166,7 @@ trait Serialization
*
* @return array|string
*/
#[ReturnTypeWillChange]
public function jsonSerialize()
{
$serializer = $this->localSerializer ?? static::$serializer;
@@ -194,4 +212,26 @@ trait Serialization
return $this;
}
private function getSleepProperties(): array
{
$properties = $this->dumpProperties;
// @codeCoverageIgnoreStart
if (!\extension_loaded('msgpack')) {
return $properties;
}
if (isset($this->constructedObjectId)) {
$this->dumpDateProperties = [
'date' => $this->format('Y-m-d H:i:s.u'),
'timezone' => serialize($this->timezone ?? null),
];
$properties[] = 'dumpDateProperties';
}
return $properties;
// @codeCoverageIgnoreEnd
}
}

View File

@@ -63,12 +63,16 @@ trait Test
*
* @param Closure|static|string|false|null $testNow real or mock Carbon instance
* @param Closure|null $callback
*
* @return mixed
*/
public static function withTestNow($testNow = null, $callback = null)
{
static::setTestNow($testNow);
$callback();
$result = $callback();
static::setTestNow();
return $result;
}
/**

View File

@@ -45,6 +45,7 @@ trait Timestamp
$delta = floor($decimal / static::MICROSECONDS_PER_SECOND);
$integer += $delta;
$decimal -= $delta * static::MICROSECONDS_PER_SECOND;
$decimal = str_pad((string) $decimal, 6, '0', STR_PAD_LEFT);
return static::rawCreateFromFormat('U u', "$integer $decimal");
}
@@ -136,6 +137,16 @@ trait Timestamp
return $this->getPreciseTimestamp(3);
}
/**
* Returns the timestamp with millisecond precision.
*
* @return int
*/
public function getTimestampMs()
{
return (int) $this->getPreciseTimestamp(3);
}
/**
* @alias getTimestamp
*
@@ -166,15 +177,15 @@ trait Timestamp
$numbers = number_format($numbers, $decimals, '.', '');
}
$sign = substr($numbers, 0, 1) === '-' ? -1 : 1;
$sign = str_starts_with($numbers, '-') ? -1 : 1;
$integer = 0;
$decimal = 0;
foreach (preg_split('`[^0-9.]+`', $numbers) as $chunk) {
[$integerPart, $decimalPart] = explode('.', "$chunk.");
$integer += \intval($integerPart);
$decimal += \floatval("0.$decimalPart");
$integer += (int) $integerPart;
$decimal += (float) ("0.$decimalPart");
}
$overflow = floor($decimal);

View File

@@ -48,7 +48,7 @@ trait Units
$seconds = (int) floor($diff / static::MICROSECONDS_PER_SECOND);
$time += $seconds;
$diff -= $seconds * static::MICROSECONDS_PER_SECOND;
$microtime = str_pad("$diff", 6, '0', STR_PAD_LEFT);
$microtime = str_pad((string) $diff, 6, '0', STR_PAD_LEFT);
$tz = $this->tz;
return $this->tz('UTC')->modify("@$time.$microtime")->tz($tz);
@@ -201,6 +201,21 @@ trait Units
$unit = CarbonInterval::make($unit);
}
// Can be removed if https://bugs.php.net/bug.php?id=81106
// is fixed
// @codeCoverageIgnoreStart
if (
$unit instanceof DateInterval &&
version_compare(PHP_VERSION, '8.1.0-dev', '>=') &&
($unit->f < 0 || $unit->f >= 1)
) {
$unit = clone $unit;
$seconds = floor($unit->f);
$unit->f -= $seconds;
$unit->s += (int) $seconds;
}
// @codeCoverageIgnoreEnd
if ($unit instanceof CarbonConverterInterface) {
return $this->resolveCarbon($unit->convertDate($this, false));
}
@@ -233,8 +248,8 @@ trait Units
{
$date = $this;
if (!is_numeric($value) || !\floatval($value)) {
return $date->isMutable() ? $date : $date->copy();
if (!is_numeric($value) || !(float) $value) {
return $date->isMutable() ? $date : $date->avoidMutation();
}
$metaUnits = [
@@ -377,7 +392,7 @@ trait Units
[$value, $unit] = [$unit, $value];
}
return $this->addUnit($unit, -\floatval($value), $overflow);
return $this->addUnit($unit, -(float) $value, $overflow);
}
/**

View File

@@ -27,7 +27,7 @@ namespace Carbon\Traits;
* @method static addWeeks(int $weeks = 1)
* @method static copy()
* @method static dayOfYear(int $dayOfYear)
* @method string getTranslationMessage(string $key, string $locale = null, string $default = null, $translator = null)
* @method string getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)
* @method static next(int|string $day = null)
* @method static startOfWeek(int $day = 1)
* @method static subWeeks(int $weeks = 1)
@@ -75,7 +75,7 @@ trait Week
$year = (int) round($year);
if ($this->weekYear(null, $dayOfWeek, $dayOfYear) === $year) {
return $this->copy();
return $this->avoidMutation();
}
$week = $this->week(null, $dayOfWeek, $dayOfYear);
@@ -103,13 +103,13 @@ trait Week
$year = $this->year;
$day = $this->dayOfYear;
$date = $this->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$date = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
if ($date->year === $year && $day < $date->dayOfYear) {
return $year - 1;
}
$date = $this->copy()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$date = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
if ($date->year === $year && $day >= $date->dayOfYear) {
return $year + 1;
@@ -151,12 +151,12 @@ trait Week
$dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0;
$dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1;
$year = $this->year;
$start = $this->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$start = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$startDay = $start->dayOfYear;
if ($start->year !== $year) {
$startDay -= $start->daysInYear;
}
$end = $this->copy()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$end = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$endDay = $end->dayOfYear;
if ($end->year !== $year) {
$endDay += $this->daysInYear;
@@ -186,8 +186,8 @@ trait Week
return $date->addWeeks(round($week) - $this->week(null, $dayOfWeek, $dayOfYear));
}
$start = $date->copy()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$end = $date->copy()->startOfWeek($dayOfWeek);
$start = $date->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
$end = $date->avoidMutation()->startOfWeek($dayOfWeek);
if ($start > $end) {
$start = $start->subWeeks(26)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);
}

View File

@@ -148,7 +148,7 @@ class Translator extends Translation\Translator
*/
public function trans($id, array $parameters = [], $domain = null, $locale = null)
{
if (null === $domain) {
if ($domain === null) {
$domain = 'messages';
}
@@ -326,7 +326,7 @@ class Translator extends Translation\Translator
$previousLocale = $this->getLocale();
if ($previousLocale === $locale) {
if ($previousLocale === $locale && isset($this->messages[$locale])) {
return true;
}
@@ -355,7 +355,7 @@ class Translator extends Translation\Translator
}
// If subtag (ex: en_CA) first load the macro (ex: en) to have a fallback
if (strpos($locale, '_') !== false &&
if (str_contains($locale, '_') &&
$this->loadMessagesFromFile($macroLocale = preg_replace('/^([^_]+).*$/', '$1', $locale))
) {
parent::setLocale($macroLocale);