Skip to content

Instantly share code, notes, and snippets.

@amnuts
Last active October 26, 2018 12:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amnuts/d60d7bfff96a650030b4a268cf39114a to your computer and use it in GitHub Desktop.
Save amnuts/d60d7bfff96a650030b4a268cf39114a to your computer and use it in GitHub Desktop.
Simple PHP timer class
<?php
/**
* Utility class to enable very simplistic timing.
*
* Usage example:
*
* $t = new Timer();
* // do something here
* echo $t;
*
* You can also mark positions:
*
* $t->mark('Step 1');
* sleep(2.24);
* $t->mark();
* usleep(327);
* $t->stop();
* echo $t;
*/
class Timer
{
protected $times = [];
protected $started = false;
protected $stopped = false;
/**
* Timer constructor
*/
public function __construct()
{
$this->times = [$this->getTimestamp('Start timer')];
$this->started = true;
$this->stopped = false;
}
/**
* Create a timestamp object
*
* @param null|string $message
* @return object
*/
protected function getTimestamp($message = null)
{
if (phpversion() < 7) {
return (object)[
'time' => microtime(true),
'message' => $message
];
}
return (object)[
'time' => date_create_immutable_from_format('U.u', microtime(true)),
'message' => $message
];
}
/**
* Mark the next timer spot
*
* @param null|string $message
* @return $this
*/
public function mark($message = null)
{
if ($this->stopped) {
return $this;
}
if ($this->started !== true) {
throw new \RuntimeException('You have not started a timer');
}
$this->times[] = $this->getTimestamp($message);
return $this;
}
/**
* Stop the timer
*
* @return $this
*/
public function stop()
{
if ($this->stopped) {
return $this;
}
if ($this->started !== true) {
throw new \RuntimeException('You have not started a timer');
}
$this->times[] = $this->getTimestamp('End timer');
$this->stopped = true;
return $this;
}
/**
* Output the timer details.
*
* If the timer has not been stopped it will just give the output with the
* start time and the delta since then. If the timer has been stopped it
* will give a fully summary with any marked positions.
*
* @return string
*/
public function __toString()
{
if ($this->started !== true) {
return 'You have not started a timer';
}
try {
if (!$this->stopped) {
$current = $this->getTimestamp('So far');
return sprintf("Started %s, current delta %s\n",
$this->getFormatted($this->times[0]->time),
$this->getDiff($current->time, $this->times[0]->time)
);
} else {
$output = '';
$total = count($this->times);
for ($i = 0; $i < $total; $i++) {
if (!$i) {
$output .= sprintf("Started %s\n", $this->getFormatted($this->times[$i]->time));
} else if ($i == ($total - 1)) {
$output .= sprintf("Ended %s, total time %s\n",
$this->getFormatted($this->times[$i]->time),
$this->getDiff($this->times[0]->time, $this->times[$i]->time)
);
} else {
$output .= sprintf("\tΔ %s%s\n",
$this->getDiff($this->times[$i-1]->time, $this->times[$i]->time),
$this->times[$i]->message ? " ({$this->times[$i]->message})" : ''
);
}
}
return $output;
}
} catch (\Exception $e) {
return 'Cannot determine timer: ' . $e->getMessage();
}
}
/**
* Represent the delta between the start and end times.
*
* @param \DateTimeInterface|float $start
* @param \DateTimeInterface|float $end
* @return string
*/
protected function getDiff($start, $end)
{
if ($start instanceof \DateTimeInterface) {
$diff = $end->diff($start, true);
return $diff->format('%dd %hh %im %s.%Fs');
}
$diff = $end - $start;
return sprintf('%0dd %0dh %0dm %0.04fs',
floor($diff / 86400),
($diff / 3600) % 24,
($diff / 60) % 60,
($diff % 60) + fmod($diff, 1)
);
}
/**
* Get formatted date/time.
*
* @param \DateTimeInterface|float $datetime
* @return false|string
*/
protected function getFormatted($datetime)
{
if ($datetime instanceof \DateTimeInterface) {
return $datetime->format('Y-m-d H:i:s');
}
return date_format(
date_create_from_format('U.u', $datetime),
'Y-m-d H:i:s'
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment