mts7/php-execution-timer

Testable PHP timer

1.2.3 2024-02-14 15:11 UTC

This package is auto-updated.

Last update: 2024-11-15 16:35:45 UTC


README

PHP timer for tracking and accumulating timings

Installation

composer require mts7/php-execution-timer

Usage

Single measurement

When measuring the time for a single event, use getDuration to find the amount of time spent on that specific functionality.

$timer = new \MtsTimer\Timer();
$timer->start();
doSomething();
$timer->stop();
echo 'Duration: ' . $timer->getDuration() . PHP_EOL;

Multiple measurements

When measuring the time for multiple events, use getTotalDuration to find the total durations of all the included functionalities.

$timer = new \MtsTimer\Timer();
for ($i = 0; $i < 5; $i++) {
    $timer->start();
    doSomething();
    $timer->stop();
    echo 'Something took ' . $timer->getDuration() . ' seconds.' . PHP_EOL;
}
echo 'Total duration: ' . $timer->getTotalDuration() . PHP_EOL;

Resetting between measurements

Some situations require having multiple accumulations that are tracked independently. For these, use reset to clear the timers and reset all internal values to 0.0..

$timer = new \MtsTimer\Timer();
$timings = [];
for ($i = 0; $i < 3; $i++) {
    $timer->reset();
    for ($j = 0; $j < 5; $j++) {
        $timer->start();
        doSomething();
        $timer->stop();    
    }
    $timings[] = $timer->getTotalDuration();
}

Testing with FixedTimer

The usual timer in the code is Timer while the tests would use FixedTimer without changing the code. Having TimerInterface is a benefit of using composition. Since both Timer and FixedTimer have similar functionality, the base functionalities are contained in AbstractTimer with overriding methods as necessary.

FixedTimer uses two constant (fixed) values (instead of the time): One for start, and another for stop.

Examples

These are very simple examples of having a class that uses the timer as well as a class that uses the class and a class that tests the class. In real-world scenarios, use a container for dependency injection and a callable that takes time.

class Benchmark
{
    public function __construct(private \MtsTimer\TimerInterface $timer)
    {
    }

    public function run(callable $callable): float
    {
        $this->timer->start();
        $callable();
        $this->timer->stop();
        
        return $this->timer->getDuration();
    }
}

class RunTheBenchmark
{
    public function execute(): float
    {
        $timer = new \MtsTimer\Timer();
        $benchmark = new Benchmark($timer);
        return $benchmark->run([self::class, 'doNothing']);
    }
    
    public static function doNothing(): void
    {
    }
}

class BenchmarkTest
{
    public function testRun(): void
    {
        $timer = new \MtsTimer\FixedTimer();
        $benchmark = new Benchmark($timer);

        $duration = $benchmark->run([RunTheBenchmark::class, 'doNothing']);
        
        $this->assertSame($timer::DURATION, $duration);
    }
}