Completed
Push — master ( a823ea...a54744 )
by Shinji
19s queued 12s
created

GetCurrentFunctionNameCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 8
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 10
rs 10
1
<?php
2
3
/**
4
 * This file is part of the sj-i/php-profiler package.
5
 *
6
 * (c) sji <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace PhpProfiler\Command\Inspector;
15
16
use PhpProfiler\Lib\Elf\Parser\ElfParserException;
17
use PhpProfiler\Lib\Elf\Process\ProcessSymbolReaderException;
18
use PhpProfiler\Lib\Elf\Tls\TlsFinderException;
19
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderException;
20
use PhpProfiler\ProcessReader\PhpGlobalsFinder;
21
use PhpProfiler\ProcessReader\PhpMemoryReader\ExecutorGlobalsReader;
22
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Symfony\Component\Console\Input\InputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use Symfony\Component\Console\Input\InputOption;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputOption was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Symfony\Component\Console\Output\ConsoleOutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Consol...\ConsoleOutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use Symfony\Component\Console\Output\OutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Output\OutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
28
final class GetCurrentFunctionNameCommand extends Command
29
{
30
    private const SLEEP_NANO_SECONDS_DEFAULT = 1000 * 1000 * 10;
31
32
    private PhpGlobalsFinder $php_globals_finder;
33
    private ExecutorGlobalsReader $executor_globals_reader;
34
35
    /**
36
     * GetCurrentFunctionNameCommand constructor.
37
     *
38
     * @param PhpGlobalsFinder $php_globals_finder
39
     * @param ExecutorGlobalsReader $executor_globals_reader
40
     * @param string|null $name
41
     */
42
    public function __construct(
43
        PhpGlobalsFinder $php_globals_finder,
44
        ExecutorGlobalsReader $executor_globals_reader,
45
        string $name = null
46
    ) {
47
        parent::__construct($name);
48
        $this->php_globals_finder = $php_globals_finder;
49
        $this->executor_globals_reader = $executor_globals_reader;
50
    }
51
52
    public function configure(): void
53
    {
54
        $this->setName('inspector:current_function')
55
            ->setDescription('periodically get running function name from an outer process or thread')
56
            ->addOption('pid', 'p', InputOption::VALUE_REQUIRED, 'process id')
57
            ->addOption(
58
                'sleep-ns',
59
                's',
60
                InputOption::VALUE_OPTIONAL,
61
                'nanoseconds between traces (default: 1000 * 1000 * 10)'
62
            );
63
    }
64
65
    /**
66
     * @param InputInterface $input
67
     * @param OutputInterface $output
68
     * @return int
69
     * @throws MemoryReaderException
70
     * @throws ProcessSymbolReaderException
71
     * @throws ElfParserException
72
     * @throws TlsFinderException
73
     */
74
    public function execute(InputInterface $input, OutputInterface $output): int
75
    {
76
        $pid = $input->getOption('pid');
77
        if (is_null($pid)) {
78
            $error_output = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
79
            $error_output->writeln('pid is not specified');
80
            return 1;
81
        }
82
        $pid = filter_var($pid, FILTER_VALIDATE_INT);
83
        if ($pid === false) {
84
            $error_output = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
85
            $error_output->writeln('pid is not integer');
86
            return 2;
87
        }
88
89
        $sleep_nano_seconds = $input->getOption('sleep-ns');
90
        if (is_null($sleep_nano_seconds)) {
91
            $sleep_nano_seconds = self::SLEEP_NANO_SECONDS_DEFAULT;
92
        }
93
        $sleep_nano_seconds = filter_var($sleep_nano_seconds, FILTER_VALIDATE_INT);
94
        if ($sleep_nano_seconds === false) {
95
            $error_output = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
96
            $error_output->writeln('sleep-ns is not integer');
97
            return 2;
98
        }
99
100
        $eg_address = $this->php_globals_finder->findExecutorGlobals($pid);
101
102
        exec('stty -icanon -echo');
103
        $keyboard_input = fopen('php://stdin', 'r');
104
        stream_set_blocking($keyboard_input, false);
0 ignored issues
show
Bug introduced by
It seems like $keyboard_input can also be of type false; however, parameter $stream of stream_set_blocking() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

104
        stream_set_blocking(/** @scrutinizer ignore-type */ $keyboard_input, false);
Loading history...
105
106
        $key = '';
107
        $count_retry = 0;
108
        while ($key !== 'q' and $count_retry < 10) {
109
            try {
110
                echo $this->executor_globals_reader->readCurrentFunctionName($pid, $eg_address) , PHP_EOL;
111
                $count_retry = 0;
112
                time_nanosleep(0, $sleep_nano_seconds);
113
            } catch (MemoryReaderException $e) {
114
                $count_retry++;
115
            }
116
            $key = fread($keyboard_input, 1);
0 ignored issues
show
Bug introduced by
It seems like $keyboard_input can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

116
            $key = fread(/** @scrutinizer ignore-type */ $keyboard_input, 1);
Loading history...
117
        }
118
119
        return 0;
120
    }
121
}
122