diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e94841162b5df96e85c00255be8d31e14b8201d5..18e17183bd451c02a86ce24eb720e16504346c37 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,75 +6,65 @@ on:
 
 name: "CI"
 
+permissions:
+  contents: read
+
 jobs:
   coding-guidelines:
-    name: "Coding Guidelines"
-
-    runs-on: "ubuntu-latest"
-
-    steps:
-      - name: "Checkout"
-        uses: "actions/checkout@v2"
+    name: Coding Guidelines
 
-      - name: "Run friendsofphp/php-cs-fixer"
-        run: "php7.4 ./tools/php-cs-fixer fix --diff-format=udiff --dry-run --show-progress=dots --using-cache=no --verbose"
-
-  type-checker:
-    name: "Type Checker"
-
-    runs-on: "ubuntu-latest"
+    runs-on: ubuntu-latest
 
     steps:
-      - name: "Checkout"
-        uses: "actions/checkout@v2"
+      - name: Checkout
+        uses: actions/checkout@v3
 
-      - name: "Update dependencies with composer"
-        run: "php7.4 ./tools/composer update --no-ansi --no-interaction --no-progress"
+      - name: Install PHP
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: 8.1
+          coverage: none
 
-      - name: "Run vimeo/psalm"
-        run: "php7.4 ./tools/psalm --config=.psalm/config.xml --no-progress --shepherd --show-info=false --stats"
+      - name: Run PHP-CS-Fixer
+        run: ./tools/php-cs-fixer fix --dry-run --show-progress=dots --using-cache=no --verbose
 
-  backward-compatibility:
-    name: Backward Compatibility
+  type-checker:
+    name: Type Checker
 
     runs-on: ubuntu-latest
 
     steps:
       - name: Checkout
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
-      - name: Fetch tags
-        run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+        uses: actions/checkout@v3
 
-      - name: Install PHP with extensions
+      - name: Install PHP
         uses: shivammathur/setup-php@v2
         with:
-          php-version: 7.4
+          php-version: 8.1
           coverage: none
-          extensions: intl
 
-      - name: Run roave/backward-compatibility-check
-        run: ./tools/roave-backward-compatibility-check --from=5.0.3
+      - name: Install dependencies with Composer
+        run: ./tools/composer update --no-interaction --no-ansi --no-progress
+
+      - name: Run Psalm
+        run: ./tools/psalm --config=.psalm/config.xml --no-progress --shepherd --show-info=false --stats
 
   tests:
-    name: "Tests"
+    name: Tests
 
-    runs-on: "ubuntu-latest"
+    runs-on: ubuntu-latest
 
     strategy:
       fail-fast: false
       matrix:
         php-version:
-          - "7.3"
-          - "7.4"
-          - "8.0"
           - "8.1"
+          - "8.2"
+          - "8.3"
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: "Install PHP with extensions"
         uses: "shivammathur/setup-php@v2"
@@ -82,17 +72,17 @@ jobs:
           php-version: "${{ matrix.php-version }}"
           coverage: "pcov"
 
-      - name: "Cache dependencies installed with composer"
-        uses: "actions/cache@v1"
+      - name: "Cache dependencies installed with Composer"
+        uses: "actions/cache@v2"
         with:
           path: "~/.composer/cache"
           key: "php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }}"
           restore-keys: "php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-"
 
-      - name: "Install dependencies with composer"
+      - name: "Install dependencies with Composer"
         run: "./tools/composer update --no-ansi --no-interaction --no-progress"
 
-      - name: "Run tests with phpunit/phpunit"
+      - name: "Run tests with PHPUnit"
         run: "vendor/bin/phpunit --coverage-clover=coverage.xml"
 
       - name: "Send code coverage report to Codecov.io"
diff --git a/.gitignore b/.gitignore
index 96c0f28a61b5cc3678e08856d17fd654592327ea..5344939da33b96017d62b73b6626d4d9819b85ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
 /.idea
-/.php_cs
-/.php_cs.cache
-/.phpunit.result.cache
+/.php-cs-fixer.php
+/.php-cs-fixer.cache
+/.phpunit.cache
 /composer.lock
 /vendor
diff --git a/.phive/phars.xml b/.phive/phars.xml
index 20a8222403a51d0634d3531f76c3d3f0c43136ee..c3faedd9f8b1f111f1ab3b3df21eea1c45ec0cef 100644
--- a/.phive/phars.xml
+++ b/.phive/phars.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <phive xmlns="https://phar.io/phive">
-  <phar name="php-cs-fixer" version="^2.16" installed="2.16.4" location="./tools/php-cs-fixer" copy="true"/>
-  <phar name="psalm" version="^4.0" installed="4.0.1" location="./tools/psalm" copy="true"/>
-  <phar name="roave/backwardcompatibilitycheck" version="^5.0.0" installed="5.0.0" location="./tools/roave-backward-compatibility-check" copy="true"/>
+  <phar name="php-cs-fixer" version="^3.0" installed="3.14.3" location="./tools/php-cs-fixer" copy="true"/>
+  <phar name="psalm" version="^5.0" installed="5.6.0" location="./tools/psalm" copy="true"/>
+  <phar name="composer" version="^2.0.3" installed="2.5.1" location="./tools/composer" copy="true"/>
 </phive>
diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php
similarity index 65%
rename from .php_cs.dist
rename to .php-cs-fixer.dist.php
index 6c1055f8f7ecb02aebc03f6f667dae9a58ca09dd..37f9d4748a6e1ae9de002290fe1c3ee9d5229f93 100644
--- a/.php_cs.dist
+++ b/.php-cs-fixer.dist.php
@@ -11,19 +11,22 @@ EOF;
 $finder = PhpCsFixer\Finder::create()
     ->files()
     ->in(__DIR__ . '/src')
-    ->in(__DIR__ . '/tests');
+    ->in(__DIR__ . '/tests')
+;
 
-return PhpCsFixer\Config::create()
-    ->setFinder($finder)
+$config = new PhpCsFixer\Config;
+$config->setFinder($finder)
     ->setRiskyAllowed(true)
     ->setRules([
         'align_multiline_comment' => true,
         'array_indentation' => true,
+        'array_push' => true,
         'array_syntax' => ['syntax' => 'short'],
+        'backtick_to_shell_exec' => true,
         'binary_operator_spaces' => [
             'operators' => [
-                '=' => 'align',
-                '=>' => 'align',
+                '=' => 'align_single_space_minimal',
+                '=>' => 'align_single_space_minimal',
             ],
         ],
         'blank_line_after_namespace' => true,
@@ -32,9 +35,12 @@ return PhpCsFixer\Config::create()
                 'break',
                 'continue',
                 'declare',
+                'default',
                 'do',
+                'exit',
                 'for',
                 'foreach',
+                'goto',
                 'if',
                 'include',
                 'include_once',
@@ -48,49 +54,90 @@ return PhpCsFixer\Config::create()
                 'yield',
             ],
         ],
-        'braces' => true,
+        'braces' => [
+            'position_after_anonymous_constructs' => 'next',
+        ],
         'cast_spaces' => true,
-        'class_attributes_separation' => ['elements' => ['const', 'method', 'property']],
+        'class_attributes_separation' => [
+            'elements' => [
+                'const' => 'one',
+                'method' => 'one',
+                'property' => 'only_if_meta'
+            ]
+        ],
+        'class_definition' => true,
+        'clean_namespace' => true,
         'combine_consecutive_issets' => true,
         'combine_consecutive_unsets' => true,
+        'combine_nested_dirname' => true,
         'compact_nullable_typehint' => true,
         'concat_space' => ['spacing' => 'one'],
+        'constant_case' => true,
         'declare_equal_normalize' => ['space' => 'none'],
         'declare_strict_types' => true,
         'dir_constant' => true,
+        'echo_tag_syntax' => true,
         'elseif' => true,
         'encoding' => true,
+        'ereg_to_preg' => true,
+        'explicit_indirect_variable' => true,
+        'explicit_string_variable' => true,
+        'fopen_flag_order' => true,
         'full_opening_tag' => true,
+        'fully_qualified_strict_types' => true,
         'function_declaration' => true,
+        'function_to_constant' => true,
+        'function_typehint_space' => true,
+        'get_class_to_class_keyword' => true,
         'global_namespace_import' => [
             'import_classes' => true,
             'import_constants' => true,
             'import_functions' => true,
         ],
         'header_comment' => ['header' => $header, 'separate' => 'none'],
+        'heredoc_to_nowdoc' => true,
+        'implode_call' => true,
+        'include' => true,
+        'increment_style' => [
+            'style' => PhpCsFixer\Fixer\Operator\IncrementStyleFixer::STYLE_POST,
+        ],
         'indentation_type' => true,
         'is_null' => true,
+        'lambda_not_used_import' => true,
         'line_ending' => true,
         'list_syntax' => ['syntax' => 'short'],
         'logical_operators' => true,
         'lowercase_cast' => true,
-        'lowercase_constants' => true,
         'lowercase_keywords' => true,
         'lowercase_static_reference' => true,
         'magic_constant_casing' => true,
-        'method_argument_space' => ['ensure_fully_multiline' => true],
+        'magic_method_casing' => true,
+        'method_argument_space' => [
+            'on_multiline' => 'ensure_fully_multiline',
+        ],
         'modernize_types_casting' => true,
         'multiline_comment_opening_closing' => true,
         'multiline_whitespace_before_semicolons' => true,
         'native_constant_invocation' => false,
         'native_function_casing' => false,
-        'native_function_invocation' => false,
-        'new_with_braces' => false,
+        'native_function_invocation' => [
+            'include' => [
+                '@internal',
+            ],
+        ],
+        'native_function_type_declaration_casing' => true,
+        'new_with_braces' => [
+            'named_class' => false,
+            'anonymous_class' => false,
+        ],
         'no_alias_functions' => true,
+        'no_alias_language_construct_call' => true,
         'no_alternative_syntax' => true,
+        'no_binary_string' => true,
         'no_blank_lines_after_class_opening' => true,
         'no_blank_lines_after_phpdoc' => true,
         'no_blank_lines_before_namespace' => true,
+        'no_break_comment' => true,
         'no_closing_tag' => true,
         'no_empty_comment' => true,
         'no_empty_phpdoc' => true,
@@ -104,31 +151,38 @@ return PhpCsFixer\Config::create()
         'no_null_property_initialization' => true,
         'no_php4_constructor' => true,
         'no_short_bool_cast' => true,
-        'no_short_echo_tag' => true,
         'no_singleline_whitespace_before_semicolons' => true,
         'no_spaces_after_function_name' => true,
+        'no_spaces_around_offset' => true,
         'no_spaces_inside_parenthesis' => true,
         'no_superfluous_elseif' => true,
         'no_superfluous_phpdoc_tags' => [
             'allow_mixed' => true,
         ],
-        'no_trailing_comma_in_list_call' => true,
-        'no_trailing_comma_in_singleline_array' => true,
+        'no_trailing_comma_in_singleline' => true,
         'no_trailing_whitespace' => true,
         'no_trailing_whitespace_in_comment' => true,
+        'no_trailing_whitespace_in_string' => true,
         'no_unneeded_control_parentheses' => true,
         'no_unneeded_curly_braces' => true,
         'no_unneeded_final_method' => true,
+        'no_unneeded_import_alias' => true,
         'no_unreachable_default_argument_value' => true,
+        'no_unset_cast' => true,
         'no_unset_on_property' => true,
         'no_unused_imports' => true,
         'no_useless_else' => true,
         'no_useless_return' => true,
+        'no_useless_sprintf' => true,
         'no_whitespace_before_comma_in_array' => true,
         'no_whitespace_in_blank_line' => true,
         'non_printable_character' => true,
         'normalize_index_brace' => true,
         'object_operator_without_whitespace' => true,
+        'operator_linebreak' => [
+            'only_booleans' => true,
+            'position' => 'end',
+        ],
         'ordered_class_elements' => [
             'order' => [
                 'use_trait',
@@ -164,42 +218,83 @@ return PhpCsFixer\Config::create()
             'direction' => 'ascend',
             'order' => 'alpha',
         ],
+        'ordered_traits' => true,
+        'php_unit_set_up_tear_down_visibility' => true,
+        'php_unit_test_case_static_method_calls' => [
+            'call_type' => 'this',
+        ],
         'phpdoc_add_missing_param_annotation' => false,
         'phpdoc_align' => true,
         'phpdoc_annotation_without_dot' => true,
         'phpdoc_indent' => true,
+        'phpdoc_inline_tag_normalizer' => true,
         'phpdoc_no_access' => true,
+        'phpdoc_no_alias_tag' => true,
         'phpdoc_no_empty_return' => true,
         'phpdoc_no_package' => true,
+        'phpdoc_no_useless_inheritdoc' => true,
         'phpdoc_order' => true,
+        'phpdoc_order_by_value' => [
+            'annotations' => [
+                'covers',
+                'dataProvider',
+                'throws',
+                'uses',
+            ],
+        ],
         'phpdoc_return_self_reference' => true,
         'phpdoc_scalar' => true,
         'phpdoc_separation' => true,
         'phpdoc_single_line_var_spacing' => true,
         'phpdoc_summary' => true,
+        'phpdoc_tag_casing' => true,
+        'phpdoc_tag_type' => true,
         'phpdoc_to_comment' => true,
         'phpdoc_trim' => true,
         'phpdoc_trim_consecutive_blank_line_separation' => true,
         'phpdoc_types' => ['groups' => ['simple', 'meta']],
         'phpdoc_types_order' => true,
+        'phpdoc_var_annotation_correct_order' => true,
         'phpdoc_var_without_name' => true,
         'pow_to_exponentiation' => true,
         'protected_to_private' => true,
         'return_assignment' => true,
         'return_type_declaration' => ['space_before' => 'none'],
         'self_accessor' => true,
+        'self_static_accessor' => true,
         'semicolon_after_instruction' => true,
         'set_type_to_cast' => true,
         'short_scalar_cast' => true,
+        'simple_to_complex_string_variable' => true,
         'simplified_null_return' => false,
         'single_blank_line_at_eof' => true,
+        'single_class_element_per_statement' => true,
         'single_import_per_statement' => true,
         'single_line_after_imports' => true,
         'single_quote' => true,
+        'single_space_after_construct' => true,
+        'single_trait_insert_per_statement' => true,
+        'space_after_semicolon' => true,
+        'standardize_increment' => true,
         'standardize_not_equals' => true,
+        'static_lambda' => true,
+        'strict_param' => true,
+        'string_line_ending' => true,
+        'switch_case_semicolon_to_colon' => true,
+        'switch_case_space' => true,
+        'switch_continue_to_break' => true,
+        'ternary_operator_spaces' => true,
+        'ternary_to_elvis_operator' => true,
         'ternary_to_null_coalescing' => true,
-        'trailing_comma_in_multiline_array' => true,
+        'trailing_comma_in_multiline' => [
+            'elements' => [
+                'arrays'
+            ]
+        ],
         'trim_array_spaces' => true,
+        'types_spaces' => [
+            'space' => 'none',
+        ],
         'unary_operator_spaces' => true,
         'visibility_required' => [
             'elements' => [
@@ -211,3 +306,5 @@ return PhpCsFixer\Config::create()
         'void_return' => true,
         'whitespace_after_comma_in_array' => true,
     ]);
+
+return $config;
diff --git a/.psalm/baseline.xml b/.psalm/baseline.xml
index 77e688e07efe46415e5eaee84fbc946c36b82bcb..4b191cdd7214d776b4a364eacf498ab9db157c30 100644
--- a/.psalm/baseline.xml
+++ b/.psalm/baseline.xml
@@ -1,2 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<files psalm-version="4.0.1@b1e2e30026936ef8d5bf6a354d1c3959b6231f44"/>
+<files psalm-version="dev-master@">
+  <file src="src/ResourceUsageFormatter.php">
+    <TypeDoesNotContainType occurrences="1">
+      <code>is_float($_SERVER['REQUEST_TIME_FLOAT'])</code>
+    </TypeDoesNotContainType>
+  </file>
+</files>
diff --git a/.psalm/config.xml b/.psalm/config.xml
index 15abef0580abbfdf63baa1a91ead072ce3fed20a..a2312368927875601649cf6dcefd85feeaec616f 100644
--- a/.psalm/config.xml
+++ b/.psalm/config.xml
@@ -4,7 +4,6 @@
     xmlns="https://getpsalm.org/schema/config"
     xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
     resolveFromConfigFile="false"
-    totallyTyped="true"
     errorBaseline=".psalm/baseline.xml"
 >
     <projectFiles>
diff --git a/ChangeLog.md b/ChangeLog.md
index 34ef7d1d70003dac658a5914d0c87c9b9e1b61dd..2814b00706ac82a487ae285ca78452947dc0f9ac 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,12 @@
 
 All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
 
+## [6.0.0] - 2023-02-03
+
+### Removed
+
+* This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0
+
 ## [5.0.3] - 2020-10-26
 
 ### Fixed
@@ -121,6 +127,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
 
 * This component is no longer supported on PHP 5.3, PHP 5.4, PHP 5.5, PHP 5.6, and PHP 7.0
 
+[6.0.0]: https://github.com/sebastianbergmann/php-timer/compare/5.0.3...6.0.0
 [5.0.3]: https://github.com/sebastianbergmann/php-timer/compare/5.0.2...5.0.3
 [5.0.2]: https://github.com/sebastianbergmann/php-timer/compare/5.0.1...5.0.2
 [5.0.1]: https://github.com/sebastianbergmann/php-timer/compare/5.0.0...5.0.1
diff --git a/LICENSE b/LICENSE
index 4193d8ae63e66dfe8b01fc1964c8535b7d7935b3..bf96e0e87ef53881a38cd25da0e803813a2b08a9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,33 +1,29 @@
-phpunit/php-timer
+BSD 3-Clause License
 
-Copyright (c) 2010-2020, Sebastian Bergmann <sebastian@phpunit.de>.
+Copyright (c) 2010-2023, Sebastian Bergmann
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
+modification, are permitted provided that the following conditions are met:
 
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
 
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
 
- * Neither the name of Sebastian Bergmann nor the names of his
-   contributors may be used to endorse or promote products derived
-   from this software without specific prior written permission.
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index a7d1e70de38f66bf280ecbc71c869319f04bd741..b553e32c69f0545e29d5ff425db48bb9e8889258 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
 # phpunit/php-timer
 
+[![Latest Stable Version](https://poser.pugx.org/phpunit/php-timer/v/stable.png)](https://packagist.org/packages/phpunit/php-timer)
 [![CI Status](https://github.com/sebastianbergmann/php-timer/workflows/CI/badge.svg)](https://github.com/sebastianbergmann/php-timer/actions)
 [![Type Coverage](https://shepherd.dev/github/sebastianbergmann/php-timer/coverage.svg)](https://shepherd.dev/github/sebastianbergmann/php-timer)
+[![codecov](https://codecov.io/gh/sebastianbergmann/php-timer/branch/main/graph/badge.svg)](https://codecov.io/gh/sebastianbergmann/php-timer)
 
 Utility class for timing things, factored out of PHPUnit into a stand-alone component.
 
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4ee967bfd2bbeb6b066646e289511de1a9f9eb4
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,9 @@
+# Security Policy
+
+This library is intended to be used in development environments only. For instance, it is used by the testing framework PHPUnit. There is no reason why this library should be installed on a webserver.
+
+**If you upload this library to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
+
+## Security Contact Information
+
+After the above, if you still would like to report a security vulnerability, please email `sebastian@phpunit.de`.
diff --git a/build.xml b/build.xml
index ebe1a8fa75fb3811b7e552fc6e2f5167ac9485e8..9dfe8807b9fcb0cd77627372fa2d14a1e3d1b003 100644
--- a/build.xml
+++ b/build.xml
@@ -22,10 +22,6 @@
             <arg value="update"/>
             <arg value="--force-accept-unsigned"/>
         </exec>
-
-        <exec executable="${basedir}/tools/composer" taskname="composer">
-            <arg value="self-update"/>
-        </exec>
     </target>
 </project>
 
diff --git a/composer.json b/composer.json
index 001701c2413f5f194eef3011b015cf373da5784d..6f5880b6aec3737a1700d4663e900279b3fe5c51 100644
--- a/composer.json
+++ b/composer.json
@@ -19,14 +19,14 @@
     },
     "prefer-stable": true,
     "require": {
-        "php": ">=7.3"
+        "php": ">=8.1"
     },
     "require-dev": {
-        "phpunit/phpunit": "^9.3"
+        "phpunit/phpunit": "^10.0"
     },
     "config": {
         "platform": {
-            "php": "7.3.0"
+            "php": "8.1.0"
         },
         "optimize-autoloader": true,
         "sort-packages": true
@@ -38,7 +38,7 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "5.0-dev"
+            "dev-main": "6.0-dev"
         }
     }
 }
diff --git a/phpunit.xml b/phpunit.xml
index 7be976b13c41a05b04e2ff5428d5f5a7283a60f0..bf94af03817ad36bfbe8e0c99a756d57250f807f 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,22 +1,22 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
          bootstrap="vendor/autoload.php"
+         cacheDirectory=".phpunit.cache"
          executionOrder="depends,defects"
-         forceCoversAnnotation="true"
-         beStrictAboutCoversAnnotation="true"
+         requireCoverageMetadata="true"
+         beStrictAboutCoverageMetadata="true"
          beStrictAboutOutputDuringTests="true"
-         beStrictAboutTodoAnnotatedTests="true"
          failOnRisky="true"
          failOnWarning="true"
-         verbose="true">
+         colors="true">
     <testsuites>
         <testsuite name="default">
-            <directory suffix="Test.php">tests</directory>
+            <directory>tests</directory>
         </testsuite>
     </testsuites>
 
-    <coverage processUncoveredFiles="true">
+    <coverage>
         <include>
             <directory suffix=".php">src</directory>
         </include>
diff --git a/src/Duration.php b/src/Duration.php
index e52bf018f28837aafb839de0021de1e02aec1a80..ef3f3bee6e3164d819811354b608efd2dc53c3a5 100644
--- a/src/Duration.php
+++ b/src/Duration.php
@@ -17,30 +17,11 @@ use function sprintf;
  */
 final class Duration
 {
-    /**
-     * @var float
-     */
-    private $nanoseconds;
-
-    /**
-     * @var int
-     */
-    private $hours;
-
-    /**
-     * @var int
-     */
-    private $minutes;
-
-    /**
-     * @var int
-     */
-    private $seconds;
-
-    /**
-     * @var int
-     */
-    private $milliseconds;
+    private readonly float $nanoseconds;
+    private readonly int $hours;
+    private readonly int $minutes;
+    private readonly int $seconds;
+    private readonly int $milliseconds;
 
     public static function fromMicroseconds(float $microseconds): self
     {
diff --git a/src/ResourceUsageFormatter.php b/src/ResourceUsageFormatter.php
index ad79262771ce155479048e2617426cf68f613f81..0c94b9b3c3e5c5ccc77963a8c2d4725747b28bde 100644
--- a/src/ResourceUsageFormatter.php
+++ b/src/ResourceUsageFormatter.php
@@ -62,7 +62,7 @@ final class ResourceUsageFormatter
     {
         foreach (self::SIZES as $unit => $value) {
             if ($bytes >= $value) {
-                return sprintf('%.2f %s', $bytes >= 1024 ? $bytes / $value : $bytes, $unit);
+                return sprintf('%.2f %s', $bytes / $value, $unit);
             }
         }
 
diff --git a/src/Timer.php b/src/Timer.php
index 0917109bebb25775038c665adf95dbab858c828a..ead2618181d369857ad284e52fbd20c28111d5d6 100644
--- a/src/Timer.php
+++ b/src/Timer.php
@@ -17,7 +17,7 @@ final class Timer
     /**
      * @psalm-var list<float>
      */
-    private $startTimes = [];
+    private array $startTimes = [];
 
     public function start(): void
     {
diff --git a/tests/DurationTest.php b/tests/DurationTest.php
index d8ba2a031c1fe551f34985797bb86e3ee7a25fd0..f39045258238ae4836c6f6e91248e47b1ee341e1 100644
--- a/tests/DurationTest.php
+++ b/tests/DurationTest.php
@@ -10,15 +10,59 @@
 namespace SebastianBergmann\Timer;
 
 use function round;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\TestDox;
+use PHPUnit\Framework\Attributes\UsesClass;
 use PHPUnit\Framework\TestCase;
 
-/**
- * @covers \SebastianBergmann\Timer\Duration
- *
- * @uses \SebastianBergmann\Timer\Timer
- */
+#[CoversClass(Duration::class)]
+#[UsesClass(Timer::class)]
 final class DurationTest extends TestCase
 {
+    /**
+     * @psalm-return list<array{0: string, 1: float}>
+     */
+    public static function durationProvider(): array
+    {
+        return [
+            ['00:00',        round((0 * 1000000))],
+            ['00:00.001',    round((.001 * 1000000))],
+            ['00:00.010',    round((.01 * 1000000))],
+            ['00:00.100',    round((.1 * 1000000))],
+            ['00:00.999',    round((.999 * 1000000))],
+            ['00:00.999',    round((.9999 * 1000000))],
+            ['00:01',        round((1 * 1000000))],
+            ['00:02',        round((2 * 1000000))],
+            ['00:59.900',    round((59.9 * 1000000))],
+            ['00:59.990',    round((59.99 * 1000000))],
+            ['00:59.999',    round((59.999 * 1000000))],
+            ['00:59.999',    round((59.9999 * 1000000))],
+            ['00:59.001',    round((59.001 * 1000000))],
+            ['00:59.010',    round((59.01 * 1000000))],
+            ['01:00',        round((60 * 1000000))],
+            ['01:01',        round((61 * 1000000))],
+            ['02:00',        round((120 * 1000000))],
+            ['02:01',        round((121 * 1000000))],
+            ['59:59.900',    round((3599.9 * 1000000))],
+            ['59:59.990',    round((3599.99 * 1000000))],
+            ['59:59.999',    round((3599.999 * 1000000))],
+            ['59:59.999',    round((3599.9999 * 1000000))],
+            ['59:59.001',    round((3599.001 * 1000000))],
+            ['59:59.010',    round((3599.01 * 1000000))],
+            ['01:00:00',     round((3600 * 1000000))],
+            ['01:00:01',     round((3601 * 1000000))],
+            ['01:00:01.900', round((3601.9 * 1000000))],
+            ['01:00:01.990', round((3601.99 * 1000000))],
+            ['01:00:01.999', round((3601.999 * 1000000))],
+            ['01:00:01.999', round((3601.9999 * 1000000))],
+            ['01:00:59.999', round((3659.9999 * 1000000))],
+            ['01:00:59.001', round((3659.001 * 1000000))],
+            ['01:00:59.010', round((3659.01 * 1000000))],
+            ['01:59:59.999', round((7199.9999 * 1000000))],
+        ];
+    }
+
     public function testCanBeCreatedFromNanoseconds(): void
     {
         $duration = Duration::fromNanoseconds(1);
@@ -39,54 +83,12 @@ final class DurationTest extends TestCase
         $this->assertSame(1.0E-6, $duration->asSeconds());
     }
 
-    /**
-     * @dataProvider durationProvider
-     * @testdox Formats $microseconds microseconds as "$string"
-     */
-    public function testCanBeFormattedAsString(string $string, int $microseconds): void
+    #[DataProvider('durationProvider')]
+    #[TestDox('Formats $microseconds microseconds as "$string"')]
+    public function testCanBeFormattedAsString(string $string, float $microseconds): void
     {
         $duration = Duration::fromMicroseconds($microseconds);
 
         $this->assertSame($string, $duration->asString());
     }
-
-    public function durationProvider(): array
-    {
-        return [
-            ['00:00',        (int) round((0 * 1000000))],
-            ['00:00.001',    (int) round((.001 * 1000000))],
-            ['00:00.010',    (int) round((.01 * 1000000))],
-            ['00:00.100',    (int) round((.1 * 1000000))],
-            ['00:00.999',    (int) round((.999 * 1000000))],
-            ['00:00.999',    (int) round((.9999 * 1000000))],
-            ['00:01',        (int) round((1 * 1000000))],
-            ['00:02',        (int) round((2 * 1000000))],
-            ['00:59.900',    (int) round((59.9 * 1000000))],
-            ['00:59.990',    (int) round((59.99 * 1000000))],
-            ['00:59.999',    (int) round((59.999 * 1000000))],
-            ['00:59.999',    (int) round((59.9999 * 1000000))],
-            ['00:59.001',    (int) round((59.001 * 1000000))],
-            ['00:59.010',    (int) round((59.01 * 1000000))],
-            ['01:00',        (int) round((60 * 1000000))],
-            ['01:01',        (int) round((61 * 1000000))],
-            ['02:00',        (int) round((120 * 1000000))],
-            ['02:01',        (int) round((121 * 1000000))],
-            ['59:59.900',    (int) round((3599.9 * 1000000))],
-            ['59:59.990',    (int) round((3599.99 * 1000000))],
-            ['59:59.999',    (int) round((3599.999 * 1000000))],
-            ['59:59.999',    (int) round((3599.9999 * 1000000))],
-            ['59:59.001',    (int) round((3599.001 * 1000000))],
-            ['59:59.010',    (int) round((3599.01 * 1000000))],
-            ['01:00:00',     (int) round((3600 * 1000000))],
-            ['01:00:01',     (int) round((3601 * 1000000))],
-            ['01:00:01.900', (int) round((3601.9 * 1000000))],
-            ['01:00:01.990', (int) round((3601.99 * 1000000))],
-            ['01:00:01.999', (int) round((3601.999 * 1000000))],
-            ['01:00:01.999', (int) round((3601.9999 * 1000000))],
-            ['01:00:59.999', (int) round((3659.9999 * 1000000))],
-            ['01:00:59.001', (int) round((3659.001 * 1000000))],
-            ['01:00:59.010', (int) round((3659.01 * 1000000))],
-            ['01:59:59.999', (int) round((7199.9999 * 1000000))],
-        ];
-    }
 }
diff --git a/tests/ResourceUsageFormatterTest.php b/tests/ResourceUsageFormatterTest.php
index a222c2c9fe0799e65965c51e01cefaf9b8ca550a..63fbd9e56686a20931a02446c828a4bc9dcd7d93 100644
--- a/tests/ResourceUsageFormatterTest.php
+++ b/tests/ResourceUsageFormatterTest.php
@@ -9,20 +9,18 @@
  */
 namespace SebastianBergmann\Timer;
 
+use PHPUnit\Framework\Attributes\BackupGlobals;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\TestDox;
+use PHPUnit\Framework\Attributes\UsesClass;
 use PHPUnit\Framework\TestCase;
 
-/**
- * @covers \SebastianBergmann\Timer\ResourceUsageFormatter
- *
- * @uses \SebastianBergmann\Timer\Duration
- * @uses \SebastianBergmann\Timer\Timer
- */
+#[CoversClass(ResourceUsageFormatter::class)]
+#[UsesClass(Duration::class)]
+#[UsesClass(Timer::class)]
 final class ResourceUsageFormatterTest extends TestCase
 {
-    /**
-     * @var ResourceUsageFormatter
-     */
-    private $formatter;
+    private ResourceUsageFormatter $formatter;
 
     protected function setUp(): void
     {
@@ -47,10 +45,8 @@ final class ResourceUsageFormatterTest extends TestCase
         );
     }
 
-    /**
-     * @backupGlobals enabled
-     * @testdox Cannot format resource usage since start of request when $_SERVER['REQUEST_TIME_FLOAT'] is not available
-     */
+    #[BackupGlobals(true)]
+    #[TestDox('Cannot format resource usage since start of request when $_SERVER[\'REQUEST_TIME_FLOAT\'] is not available')]
     public function testCannotFormatResourceUsageSinceStartOfRequestWhenRequestTimeFloatIsNotAvailable(): void
     {
         unset($_SERVER['REQUEST_TIME_FLOAT']);
@@ -60,10 +56,8 @@ final class ResourceUsageFormatterTest extends TestCase
         $this->formatter->resourceUsageSinceStartOfRequest();
     }
 
-    /**
-     * @backupGlobals enabled
-     * @testdox Cannot format resource usage since start of request when $_SERVER['REQUEST_TIME_FLOAT'] is not valid
-     */
+    #[BackupGlobals(true)]
+    #[TestDox('Cannot format resource usage since start of request when $_SERVER[\'REQUEST_TIME_FLOAT\'] is not valid')]
     public function testCannotFormatResourceUsageSinceStartOfRequestWhenRequestTimeFloatIsNotValid(): void
     {
         $_SERVER['REQUEST_TIME_FLOAT'] = 'string';
diff --git a/tests/TimerTest.php b/tests/TimerTest.php
index 79601a58240b61a16c4933e34f0b1ec48c6b3599..46eb9d502a7b3ceb4db99211761c30e8843f80a8 100644
--- a/tests/TimerTest.php
+++ b/tests/TimerTest.php
@@ -9,19 +9,15 @@
  */
 namespace SebastianBergmann\Timer;
 
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\UsesClass;
 use PHPUnit\Framework\TestCase;
 
-/**
- * @covers \SebastianBergmann\Timer\Timer
- *
- * @uses \SebastianBergmann\Timer\Duration
- */
+#[CoversClass(Timer::class)]
+#[UsesClass(Duration::class)]
 final class TimerTest extends TestCase
 {
-    /**
-     * @var Timer
-     */
-    private $timer;
+    private Timer $timer;
 
     protected function setUp(): void
     {