1 <?php
2
3 /**
4 * Class to stop the script time.
5 *
6 * @author gharlan
7 *
8 * @package redaxo\core
9 */
10 class rex_timer
11 {
12 const SEC = 1;
13 const MILLISEC = 1000;
14 const MICROSEC = 1000000;
15
16 public static $serverTimings = [];
17
18 private $start;
19 private $duration;
20
21 /**
22 * Constructor.
23 *
24 * @param float $start Start time
25 */
26 public function __construct($start = null)
27 {
28 if ($start) {
29 $this->start = $start;
30 } else {
31 $this->reset();
32 }
33 }
34
35 /**
36 * Measures the runtime of the given callable.
37 *
38 * On sufficient user permissions - or in debug mode - this timings will be sent over the wire to the browser via server timing api http headers.
39 *
40 * @param string $label
41 * @param callable $callable
42 *
43 * @return mixed result of callable
44 */
45 public static function measure($label, callable $callable)
46 {
47 static $enabled = false;
48
49 // we might get called very early in the process, in which case we can't determine yet whether the user is logged in.
50 // this also means, in debug-mode we get more timings in comparison to admin-only timings.
51 if (!$enabled) {
52 // dont create the user (can cause session locks), to prevent influencing the things we try to measure.
53 $enabled = rex::isDebugMode() || ($user = rex::getUser()) && $user->isAdmin();
54 }
55
56 if (!$enabled) {
57 return $callable();
58 }
59
60 $timer = new self();
61 $result = $callable();
62 $timer->stop();
63
64 $duration = isset(self::$serverTimings[$label]) ? self::$serverTimings[$label] : 0;
65 $duration += $timer->getDelta(self::MILLISEC);
66
67 self::$serverTimings[$label] = $duration;
68
69 return $result;
70 }
71
72 /**
73 * Resets the timer.
74 */
75 public function reset()
76 {
77 $this->start = microtime(true);
78 }
79
80 /**
81 * Stops the timer.
82 */
83 public function stop()
84 {
85 $this->duration = microtime(true) - $this->start;
86 }
87
88 /**
89 * Returns the time difference.
90 *
91 * @param int $precision Factor which will be multiplied, for convertion into different units (e.g. 1000 for milli,...)
92 *
93 * @return float Time difference
94 */
95 public function getDelta($precision = self::MILLISEC)
96 {
97 $duration = null === $this->duration ? microtime(true) - $this->start : $this->duration;
98
99 return $duration * $precision;
100 }
101
102 /**
103 * Returns the formatted time difference.
104 *
105 * @param int $precision Factor which will be multiplied, for convertion into different units (e.g. 1000 for milli,...)
106 * @param int $decimals Number of decimals points
107 *
108 * @return string Formatted time difference
109 */
110 public function getFormattedDelta($precision = self::MILLISEC, $decimals = 3)
111 {
112 $time = $this->getDelta($precision);
113 return rex_formatter::number($time, [$decimals]);
114 }
115 }
116