AbstractTimer::bounds()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 2
rs 10
1
<?php declare(strict_types=1);
2
3
namespace AlecRabbit\Timers\Core;
4
5
use AlecRabbit\Formatters\Contracts\TimerReportFormatterInterface;
6
use AlecRabbit\Reports\Core\AbstractReportable;
7
use AlecRabbit\Timers\Contracts\TimerInterface;
8
use AlecRabbit\Timers\Core\Traits\TimerFields;
9
10
/**
11
 * Class AbstractTimer
12
 */
13
abstract class AbstractTimer extends AbstractReportable implements TimerInterface
14
{
15
    use TimerFields;
16
17
    /**
18
     * Timer constructor.
19
     * @param null|string $name
20
     * @param bool $start
21
     * @throws \Exception
22
     */
23 39
    public function __construct(?string $name = null, bool $start = true)
24
    {
25 39
        parent::__construct();
26 39
        $this->checkEnvironment();
27 39
        $this->name = $this->defaultName($name);
28 39
        $this->creationTime = new \DateTimeImmutable();
29 39
        $this->computeElapsed();
30 39
        if ($start) {
31 27
            $this->start();
32
        }
33 39
    }
34
35 19
    protected function checkEnvironment(): void
36
    {
37 19
    }
38
39
    /**
40
     * @throws \Exception
41
     */
42 39
    protected function computeElapsed(): void
43
    {
44 39
        $this->elapsed = (new \DateTimeImmutable())->diff($this->creationTime);
45 39
    }
46
47
    /**
48
     * Starts the timer.
49
     *
50
     * @return void
51
     */
52 32
    public function start(): void
53
    {
54 32
        if ($this->isNotStarted()) {
55 32
            $this->previous = $this->current();
56
        }
57 32
        $this->started = true;
58 32
    }
59
60
    abstract public function current();
61
62
    /**
63
     * Marks the time.
64
     * If timer was not started starts the timer.
65
     * @param int|null $iterationNumber
66
     * @return self
67
     */
68 7
    public function check(?int $iterationNumber = null): self
69
    {
70 7
        if ($this->isStopped()) {
71 1
            throw new \RuntimeException('Timer[' . $this->name . '] is already stopped.');
72
        }
73 7
        if ($this->isNotStarted()) {
74 2
            $this->start();
75
        } else {
76 7
            $this->mark($iterationNumber);
77
        }
78 7
        return $this;
79
    }
80
81
    /**
82
     * @param int|null $iterationNumber
83
     */
84 7
    protected function mark(?int $iterationNumber = null): void
85
    {
86 7
        $current = $this->current();
87 7
        $this->currentValue = $current - $this->previous;
88 7
        $this->previous = $current;
89
90 7
        $this->compute($iterationNumber);
91 7
    }
92
93
    /**
94
     * @param null|int $iterationNumber
95
     */
96 12
    protected function compute(?int $iterationNumber): void
97
    {
98 12
        if (0 !== $this->count) {
99 11
            ++$this->count;
100 11
            $this->checkMinValue($iterationNumber);
101 11
            $this->checkMaxValue($iterationNumber);
102 11
            $this->computeAverage();
103
        } else {
104 12
            $this->initValues();
105
        }
106 12
    }
107
108
    /**
109
     * @param null|int $iterationNumber
110
     */
111 11
    protected function checkMinValue(?int $iterationNumber): void
112
    {
113 11
        if ($this->currentValue < $this->minValue) {
114 5
            $this->minValue = $this->currentValue;
115 5
            $this->minValueIteration = $iterationNumber ?? $this->count;
116
        }
117 11
    }
118
119
    /**
120
     * @param null|int $iterationNumber
121
     */
122 11
    protected function checkMaxValue(?int $iterationNumber): void
123
    {
124 11
        if ($this->currentValue > $this->maxValue) {
125 8
            $this->maxValue = $this->currentValue;
126 8
            $this->maxValueIteration = $iterationNumber ?? $this->count;
127
        }
128 11
    }
129
130 11
    protected function computeAverage(): void
131
    {
132 11
        $this->avgValue = (($this->avgValue * ($this->count - 1)) + $this->currentValue) / $this->count;
133 11
    }
134
135 12
    protected function initValues(): void
136
    {
137 12
        $this->maxValueIteration = $this->minValueIteration = $this->count = 1;
138 12
        $this->maxValue = $this->currentValue;
139 12
        $this->minValue = $this->currentValue;
140 12
        $this->avgValue = $this->currentValue;
141 12
    }
142
143
    /**
144
     * Stops the timer and returns elapsed time string.
145
     * @return string
146
     * @throws \Exception
147
     */
148 5
    public function elapsed(): string
149
    {
150 5
        if ($this->isNotStopped()) {
151 5
            $this->stop();
152
        }
153
        return
154 5
            $this->formattedElapsed();
155
    }
156
157
    /**
158
     * Stops the timer.
159
     * @throws \Exception
160
     */
161 6
    public function stop(): void
162
    {
163 6
        $this->computeElapsed();
164 6
        $this->stopped = true;
165 6
    }
166
167
    /**
168
     * @return string
169
     * @throws \Exception
170
     */
171 5
    protected function formattedElapsed(): string
172
    {
173 5
        $formatter = $this->report()->getFormatter();
174 5
        if ($formatter instanceof TimerReportFormatterInterface) {
175 5
            return $formatter->formatElapsed($this->elapsed);
176
        }
177
        // @codeCoverageIgnoreStart
178
        return
179
            $this->elapsed->format('%ss');
180
        // @codeCoverageIgnoreEnd
181
    }
182
183
    /**
184
     * @return \DateInterval
185
     * @throws \Exception
186
     */
187 15
    public function getElapsed(): \DateInterval
188
    {
189 15
        if ($this->isNotStopped()) {
190 14
            $this->computeElapsed();
191
        }
192 15
        return $this->elapsed;
193
    }
194
195
    /**
196
     * @param int|float $start
197
     * @param int|float $stop
198
     * @param null|int $iterationNumber
199
     * @return self
200
     */
201 9
    public function bounds($start, $stop, ?int $iterationNumber = null): self
202
    {
203 9
        $this->assertStartAndStop($start, $stop);
204 5
        if ($this->isNotStarted()) {
205 1
            $this->start();
206
        }
207 5
        $this->updateCurrentAndPrevious($start, $stop);
208
209 5
        $this->compute($iterationNumber);
210 5
        return $this;
211
    }
212
213
    /**
214
     * @psalm-suppress MissingParamType
215
     */
216
    abstract protected function assertStartAndStop(/** @noinspection PhpDocSignatureInspection */ $start, $stop): void;
217
218
    /**
219
     * @param float $start
220
     * @param float $stop
221
     */
222 5
    protected function updateCurrentAndPrevious($start, $stop): void
223
    {
224 5
        $this->currentValue = $stop - $start;
225 5
        $this->previous = $stop;
226 5
    }
227
}
228