Passed
Pull Request — 1.x (#334)
by Akihito
02:28
created

OpenContext   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 62
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 25
dl 0
loc 62
rs 10
c 1
b 0
f 0
wmc 8

4 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 3 1
A getXdebugId() 0 3 1
A __construct() 0 29 5
A jsonSerialize() 0 6 1
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
        // Always generate an ID for profiling context, regardless of Xdebug availability
53
        $xdebugId = uniqid('profile_', true);
54
        self::$xdebugIdMap[spl_object_hash($this)] = $xdebugId;
55
56
        if (! extension_loaded('xdebug') || ! function_exists('xdebug_start_trace')) {
57
            return; // @codeCoverageIgnore
58
        }
59
60
        // Stop any existing trace first to ensure clean start
61
        @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

61
        /** @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...
62
63
        // Use full path for trace file to ensure consistency with xhprofFile
64
        $outputDir = ini_get('xdebug.output_dir');
65
        if ($outputDir === false) {
66
            $outputDir = sys_get_temp_dir(); // @codeCoverageIgnore
67
        }
68
69
        $traceFilePrefix = rtrim($outputDir, '/') . '/' . $xdebugId;
70
        @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

70
        /** @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...
71
    }
72
73
    public static function create(AbstractRequest $request): self
74
    {
75
        return new self($request);
76
    }
77
78
    public function getXdebugId(): ?string
79
    {
80
        return self::$xdebugIdMap[spl_object_hash($this)] ?? null;
81
    }
82
83
    /** @return array<string, mixed> */
84
    #[Override]
85
    public function jsonSerialize(): array
86
    {
87
        return [
88
            'method' => $this->method,
89
            'uri' => $this->uri,
90
        ];
91
    }
92
}
93