Passed
Pull Request — 1.x (#334)
by Akihito
12:50 queued 10:32
created

OpenContext::__construct()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 14
nc 6
nop 1
dl 0
loc 28
rs 9.4888
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource\SemanticLog\Profile\Verbose;
6
7
use BEAR\Resource\AbstractRequest;
8
use JsonSerializable;
9
use Koriym\SemanticLogger\AbstractContext;
10
use Override;
11
12
use function extension_loaded;
13
use function function_exists;
14
use function ini_get;
15
use function rtrim;
16
use function spl_object_hash;
17
use function strtoupper;
18
use function sys_get_temp_dir;
19
use function uniqid;
20
use function xdebug_start_trace;
21
use function xdebug_stop_trace;
22
use function xhprof_enable;
23
24
use const XHPROF_FLAGS_CPU;
25
use const XHPROF_FLAGS_MEMORY;
26
use const XHPROF_FLAGS_NO_BUILTINS;
27
28
final class OpenContext extends AbstractContext implements JsonSerializable
29
{
30
    /** @psalm-suppress InvalidClassConstantType */
31
    public const TYPE = 'bear_resource_request';
32
33
    /** @psalm-suppress InvalidClassConstantType */
34
    public const SCHEMA_URL = 'https://bearsunday.github.io/BEAR.Resource/schemas/open-context.json';
35
36
    public readonly string $method;
37
    public readonly string $uri;
38
39
    /** @var array<string, string|null> */
40
    private static array $xdebugIdMap = [];
41
42
    public function __construct(AbstractRequest $request)
43
    {
44
        $this->method = strtoupper($request->method);
0 ignored issues
show
Bug introduced by
The property method is declared read-only in BEAR\Resource\SemanticLo...ile\Verbose\OpenContext.
Loading history...
45
        $this->uri = $request->toUri();
0 ignored issues
show
Bug introduced by
The property uri is declared read-only in BEAR\Resource\SemanticLo...ile\Verbose\OpenContext.
Loading history...
46
47
        // if xhprof is enabled, start profiling
48
        if (function_exists('xhprof_enable')) {
49
            xhprof_enable(XHPROF_FLAGS_NO_BUILTINS | XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY);
50
        }
51
52
        if (! extension_loaded('xdebug') || ! function_exists('xdebug_start_trace')) {
53
            return; // @codeCoverageIgnore
54
        }
55
56
        $xdebugId = uniqid('xhprof_', true);
57
        self::$xdebugIdMap[spl_object_hash($this)] = $xdebugId;
58
59
        // Stop any existing trace first to ensure clean start
60
        @xdebug_stop_trace();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for xdebug_stop_trace(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

60
        /** @scrutinizer ignore-unhandled */ @xdebug_stop_trace();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
61
62
        // Use full path for trace file to ensure consistency with xhprofFile
63
        $outputDir = ini_get('xdebug.output_dir');
64
        if ($outputDir === false) {
65
            $outputDir = sys_get_temp_dir(); // @codeCoverageIgnore
66
        }
67
68
        $traceFilePrefix = rtrim($outputDir, '/') . '/' . $xdebugId;
69
        @xdebug_start_trace($traceFilePrefix);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for xdebug_start_trace(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

69
        /** @scrutinizer ignore-unhandled */ @xdebug_start_trace($traceFilePrefix);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
70
    }
71
72
    public static function create(AbstractRequest $request): self
73
    {
74
        return new self($request);
75
    }
76
77
    public function getXdebugId(): ?string
78
    {
79
        return self::$xdebugIdMap[spl_object_hash($this)] ?? null;
80
    }
81
82
    /** @return array<string, mixed> */
83
    #[Override]
84
    public function jsonSerialize(): array
85
    {
86
        return [
87
            'method' => $this->method,
88
            'uri' => $this->uri,
89
        ];
90
    }
91
}
92