# php-timer: a stopwatch and memory reporter for PHP code, without a framework

> phpunit/php-timer is the timing utility factored out of PHPUnit into a standalone Composer package. It measures elapsed time and formats time plus memory into one line, and it is small enough that the interesting questions are about its API shape and its limits.

**sebastianbergmann/php-timer** — Utility class for timing

- Repository: https://github.com/sebastianbergmann/php-timer
- Stars: 7,737 · Forks: 63
- Language: PHP
- License: BSD-3-Clause
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/sebastianbergmann-php-timer

## The problem php-timer solves: elapsed time without a framework

Measuring how long a block of PHP takes usually means calling microtime(true) twice and subtracting, then formatting the float yourself. That works until you want the same measurement in six places, or you want memory next to it. php-timer is the timing code factored out of PHPUnit into a standalone component, so a script, a CLI command or a small service can get the same Duration object PHPUnit uses without pulling in the test framework.

The audience is narrow and specific. It is for developers who already think in PHPUnit terms and want the same numbers outside a test run, and for anyone building a small profiler or a one-line resource report. It is not a general-purpose instrumentation library, and the README does not present it as one.

## How the Timer and Duration objects fit together

The mechanism is a stopwatch with a typed result. You construct a Timer, call start(), run your code, and call stop(). stop() does not return a float. It returns an object of class SebastianBergmann\Timer\Duration, and the README's own var_dump output shows the class name as string(32) "SebastianBergmann\Timer\Duration".

The Duration object is where the design decision sits. Instead of forcing one representation on you, it exposes asString(), asSeconds(), asMilliseconds(), asMicroseconds() and asNanoseconds(). In the README example the four numeric forms of one measurement come out as float(0.002851062), float(2.851062), float(2851.062) and int(2851062), which means the conversion happens at read time and you pick the unit that matches your output. asString() returns the compact form "00:00.002", minutes and seconds with millisecond precision, which is what PHPUnit prints.

A second class handles the reporting layer. ResourceUsageFormatter::resourceUsage() takes a Duration and returns a single string containing both time and memory, printed in the README as "Time: 00:00.002, Memory: 6.00 MB". The memory figure comes from PHP's own memory reporting, so it reflects the process at the moment the formatter runs, not a peak tracked by the library. The repository layout is consistent with that split: src/ holds the classes, tests/ the test suite, and the package ships phpstan.neon, phpunit.xml and .php-cs-fixer.dist.php for its own quality checks.

## Installing php-timer with Composer and timing your first loop

The README gives two Composer commands. Use the first if the timer is part of your application, the second if it only runs during development, for instance inside a test suite.

```bash
composer require phpunit/php-timer
```

```bash
composer require --dev phpunit/php-timer
```

The README's basic example requires the Composer autoloader, imports the Timer class, starts the timer, runs a loop, and stops it. Running it should print the class name of the returned object followed by the five representations of the same duration.

```php
require __DIR__ . '/vendor/autoload.php';

use SebastianBergmann\Timer\Timer;

$timer = new Timer;

$timer->start();

foreach (\range(0, 100000) as $i) {
    // ...
}

$duration = $timer->stop();

var_dump(get_class($duration));
var_dump($duration->asString());
var_dump($duration->asSeconds());
var_dump($duration->asMilliseconds());
var_dump($duration->asMicroseconds());
var_dump($duration->asNanoseconds());
```

For a one-line report instead of six var_dumps, the README passes the Duration to the formatter and prints the result. The output it documents is a single line with time and memory.

```php
use SebastianBergmann\Timer\ResourceUsageFormatter;
use SebastianBergmann\Timer\Timer;

$timer = new Timer;
$timer->start();

foreach (\range(0, 100000) as $i) {
    // ...
}

print (new ResourceUsageFormatter)->resourceUsage($timer->stop());
```

The third documented entry point skips the timer entirely. resourceUsageSinceStartOfRequest() measures from PHP startup rather than from a start() call, and the README labels the $_SERVER['REQUEST_TIME_FLOAT'] value it depends on as unreliable. Treat that method as a convenience for a quick report, not as an accurate measurement.

## Where php-timer stops being the right tool

The library measures elapsed time; it does not control it. There is no timeout, no cancellation, no callback when a threshold is crossed. If you need to interrupt a long-running loop, you set that limit in PHP itself, not here. The README documents no such feature, and the class names in the usage examples are Timer, Duration and ResourceUsageFormatter, none of which implies enforcement.

Two smaller constraints matter in practice. First, the elapsed time is wall-clock time, so a process that blocks on I/O and one that burns CPU for the same number of milliseconds are indistinguishable in the output; the README documents no CPU-time variant. Second, the memory figure in resourceUsage() is a point-in-time reading, and the README does not describe peak tracking, so a report built on it will understate a spike that has already been released. If you need peak memory, read PHP's peak usage yourself and format it alongside the Duration.

The API is also deliberately thin. A single Timer instance holds one start point, so overlapping measurements need separate instances, and the README gives no example of nesting or pausing. Anyone who needs a hierarchy of named spans, or output that can be loaded into a tracing viewer, is outside what this package offers.

## php-timer against microtime() and against a full profiler

The obvious alternative is microtime() itself. The difference is not accuracy, it is the shape of the result. microtime(true) gives you a float in seconds, and every formatting decision, unit conversion and label is yours to write. php-timer wraps the same kind of measurement in a Duration object with named accessors and a fixed string format, and adds the memory line through ResourceUsageFormatter. If you need one measurement in one script, microtime() is fewer moving parts. If you need the same output in several places, the formatter is the reason to take the dependency.

The other direction is a profiler such as Xdebug or a sampling profiler. Those answer a different question: which function inside the loop is slow. php-timer tells you the loop took 2.851062 milliseconds and nothing about where that time went. Choosing between them is a question of whether you are reporting a duration or investigating one, and the two are complementary rather than competing.

## Versions, licence and the cost of keeping php-timer current

The package follows PHPUnit's own release cadence. The recent tags are 9.0.0 on 2026-02-06, 8.0.0 on 2025-02-07 and 7.0.1 on 2024-07-03, and the last push to the default branch was on 2026-09-17. Major versions arrive roughly once a year, and the repository carries renovate.json, so dependency updates are automated on the maintainer's side.

That cadence has a cost for consumers. A major version bump in this family typically tracks a new PHP requirement, and the README does not state the supported PHP versions, so the constraint to check is the one in composer.json. If your project pins an older PHPUnit, its transitive php-timer constraint may hold you back, and a direct dependency on php-timer 9.0.0 can then conflict. The safest pattern is to let PHPUnit pull the package in when you are already using PHPUnit, and to add it directly only for standalone scripts.

The licence is BSD-3-Clause, as stated in the repository's LICENSE file. That is a permissive licence, so redistributing the package inside a larger work is generally allowed provided the copyright notice and licence text are kept, but the details depend on how you ship it and this is not legal advice. The practical obligation is to keep the LICENSE file with any copy you redistribute.

## Conclusion

Adopt phpunit/php-timer if you want PHPUnit's own timing semantics in a script that has no test framework attached, or if you already depend on PHPUnit and want the same Duration object in application code. Do not adopt it for wall-clock scheduling, countdowns or request time limits: it measures elapsed time, it does not enforce anything, and resourceUsageSinceStartOfRequest() rests on $_SERVER['REQUEST_TIME_FLOAT'], which the README itself calls unreliable. Before wiring it into a report, run the basic example from the README and confirm that asString() gives you the three-part HH:MM.mmm format your log parser expects, and check that 9.0.0 matches the PHP version constraint in your composer.json.

## FAQ

### How do I use the microtime() function in PHP, and how is php-timer different?

microtime() returns a timestamp, so you call it before and after your code and subtract the two values yourself. php-timer does that subtraction internally: you call start() and stop(), and stop() returns a Duration object with asString(), asSeconds(), asMilliseconds(), asMicroseconds() and asNanoseconds().

### How do I set a time limit in PHP with php-timer?

You cannot. php-timer only measures elapsed time and reports it; the README documents no timeout, cancellation or threshold behaviour. Time limits are set in PHP itself, not through this package.

### How do I install php-timer?

Add it to a project with composer require phpunit/php-timer, or use composer require --dev phpunit/php-timer when it is only needed during development, such as inside a test suite. Both commands are given in the README.

### Can php-timer report memory usage as well as time?

Yes, through ResourceUsageFormatter. Passing a Duration to resourceUsage() returns one line containing both time and memory, which the README shows as "Time: 00:00.002, Memory: 6.00 MB". The memory value is a reading taken when the formatter runs, not a tracked peak.

### What does php-timer's asString() output look like?

The README's basic example shows asString() returning "00:00.002": minutes, seconds and milliseconds. The same Duration also exposes the value as seconds, milliseconds, microseconds and nanoseconds.

## Sources

- [Issues](https://github.com/sebastianbergmann/php-timer/issues)
- [License: BSD-3-Clause](https://github.com/sebastianbergmann/php-timer/blob/main/LICENSE)
- [README](https://github.com/sebastianbergmann/php-timer/blob/main/README.md)
- [Releases](https://github.com/sebastianbergmann/php-timer/releases)
- [sebastianbergmann/php-timer on GitHub](https://github.com/sebastianbergmann/php-timer)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sebastianbergmann-php-timer
