Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
Location
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
5 / 5
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fromThrowable
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 fromBacktrace
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 __toString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 normalizeLine
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Boiler;
6
7use Throwable;
8
9/** @api */
10final readonly class Location
11{
12    public function __construct(
13        public string $path,
14        public ?int $line = null,
15    ) {}
16
17    public static function fromThrowable(string $path, Throwable $throwable): self
18    {
19        if ($throwable->getFile() === $path) {
20            return new self($path, self::normalizeLine($throwable->getLine()));
21        }
22
23        foreach ($throwable->getTrace() as $frame) {
24            if (($frame['file'] ?? null) !== $path) {
25                continue;
26            }
27
28            return new self($path, self::normalizeLine($frame['line'] ?? null));
29        }
30
31        return new self($path);
32    }
33
34    public static function fromBacktrace(string $path): self
35    {
36        foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
37            if (($frame['file'] ?? null) !== $path) {
38                continue;
39            }
40
41            return new self($path, self::normalizeLine($frame['line'] ?? null));
42        }
43
44        return new self($path);
45    }
46
47    public function __toString(): string
48    {
49        return $this->line === null
50            ? $this->path
51            : "{$this->path}:{$this->line}";
52    }
53
54    private static function normalizeLine(mixed $line): ?int
55    {
56        return is_int($line) && $line > 0 ? $line : null;
57    }
58}