Completed
Push — develop ( eb616e...328010 )
by Alec
03:31
created

AbstractTimer::setTimeFunction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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