Completed
Pull Request — master (#85)
by Jarrett
05:37
created

XhprofCollector::getFlags()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 20
ccs 0
cts 16
cp 0
rs 8.8571
cc 5
eloc 13
nc 5
nop 0
crap 30
1
<?php
2
3
namespace Jns\Bundle\XhprofBundle\DataCollector;
4
5
// supports 2.0, 2.1 LoggerInterface
6
use Symfony\Component\HttpKernel\Log\LoggerInterface as HttpKernelLoggerInterface;
7
use Psr\Log\LoggerInterface as PsrLoggerInterface;
8
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
12
use Symfony\Component\DependencyInjection\ContainerInterface;
13
use Doctrine\Common\Persistence\ManagerRegistry;
14
use Jns\Bundle\XhprofBundle\Document\XhguiRuns as XhguiRuns_Document;
15
use Jns\Bundle\XhprofBundle\Entity\XhguiRuns as XhguiRuns_Entity;
16
use Doctrine\ODM\MongoDB\DocumentManager;
17
18
/**
19
 * XhprofDataCollector.
20
 *
21
 * @author Jonas Wouters <[email protected]>
22
 */
23
class XhprofCollector extends DataCollector
24
{
25
    protected $container;
26
    protected $logger;
27
    protected $runId;
28
    protected $doctrine;
29
    protected $collecting = false;
30
    protected $collectingRequest;
31
32 3
    public function __construct(ContainerInterface $container, $logger = null, ManagerRegistry $doctrine = null)
33
    {
34 3
        $this->container = $container;
35
36 3
        if ($logger !== null && !$logger instanceof HttpKernelLoggerInterface && !$logger instanceof PsrLoggerInterface) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\HttpKernel\Log\LoggerInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
37
            throw new \InvalidArgumentException('Logger must be an instance of Symfony\Component\HttpKernel\Log\LoggerInterface or Psr\Log\LoggerInterface');
38
        }
39
40 3
        $this->logger    = $logger;
41 3
        $this->doctrine  = $doctrine;
42 3
        $this->data['xhprof_extension_exists'] = function_exists('xhprof_enable') || function_exists('tideways_enable');
43 3
        $this->data['xhprof'] = null;
44 3
        $this->data['source'] = null;
45 3
        $this->data['xhprof_url'] = null;
46 3
    }
47
48
    /**
49
     * {@inheritdoc}
50
     *
51
     * Prepare data for the debug toolbar.
52
     */
53
    public function collect(Request $request, Response $response, \Exception $exception = null)
54
    {
55
        if (!$this->runId && $request === $this->collectingRequest) {
56
            $this->stopProfiling($request->getHost(), $request->getUri());
57
        }
58
    }
59
60
    /**
61
     * Start profiling with probability according to sample size.
62
     *
63
     * @return boolean whether profiling was started or not.
64
     */
65
    public function startProfiling(Request $request = null)
66
    {
67
        if (!$this->getXhprofExtensionExists() || mt_rand(1, $this->container->getParameter('jns_xhprof.sample_size')) != 1) {
68
            return false;
69
        }
70
71
        $this->collecting = true;
72
        $this->collectingRequest = $request;
73
74
        switch (true) {
75
            case function_exists('xhprof_enable'):
76
                xhprof_enable($this->getFlags());
77
                break;
78
79
            case function_exists('tideways_enable'):
80
                tideways_enable($this->getFlags());
81
                break;
82
        }
83
84
        if ($this->logger) {
85
            $this->logger->debug('Enabled XHProf');
86
        }
87
88
        return true;
89
    }
90
91
    /**
92
     * Calculate the flags for xhprof_enable
93
     *
94
     * @return int
95
     */
96
    private function getFlags()
97
    {
98
        switch (true) {
99
            case function_exists('xhprof_enable'):
100
                $flags = XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY;
101
                if ($this->container->getParameter('jns_xhprof.skip_builtin_functions') === true) {
102
                    $flags |= XHPROF_FLAGS_NO_BUILTINS;
103
                }
104
                break;
105
106
            case function_exists('tideways_enable'):
107
                $flags = TIDEWAYS_FLAGS_CPU | TIDEWAYS_FLAGS_MEMORY;
108
                if ($this->container->getParameter('jns_xhprof.skip_builtin_functions') === true) {
109
                    $flags |= TIDEWAYS_FLAGS_NO_BUILTINS;
110
                }
111
                break;
112
        }
113
114
        return $flags;
0 ignored issues
show
Bug introduced by
The variable $flags does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
115
    }
116
117
    /**
118
     * Stop profiling if we where profiling.
119
     *
120
     * @param string $serverName The server name the request is running on, or cli for command line.
121
     * @param string $uri        The requested uri / command name.
122
     *
123
     * @return bool
124
     */
125
    public function stopProfiling($serverName, $uri)
126
    {
127
        if (isset($this->data['xhprof'])) {
128
            return $this->data['xhprof'];
129
        }
130
131
        if (!$this->collecting) {
132
            return $this->data['xhprof'] ? $this->data['xhprof'] : false;
133
        }
134
135
        $this->collecting = false;
136
137
        switch (true) {
138
            case function_exists('xhprof_disable'):
139
                $xhprof_data = xhprof_disable();
140
                break;
141
142
            case function_exists('tideways_disable'):
143
                $xhprof_data = tideways_disable();
144
                break;
145
        }
146
147
        if ($this->logger) {
148
            $this->logger->debug('Disabled XHProf');
149
        }
150
151
        $xhprof_runs = $this->createRun($serverName, $uri);
152
        $source = null;
153
154
        if ($xhprof_runs instanceof \XHProfRuns_Default) {
155
            $source = $this->sanitizeUriForSource($uri);
156
        }
157
158
        $this->runId = $xhprof_runs->save_run($xhprof_data, $source);
0 ignored issues
show
Bug introduced by
The variable $xhprof_data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
159
160
        $this->data = array(
161
            'xhprof' => $this->runId,
162
            'source' => $source,
163
        );
164
165
        if ($xhprof_runs instanceof XhguiRuns_Document) {
166
            $this->data['xhprof_url'] = $this->container->getParameter('jns_xhprof.location_web') . '/run/view?id=' . $this->data['xhprof'];
167
        } else {
168
            $this->data['xhprof_url'] = $this->container->getParameter('jns_xhprof.location_web') . '?run=' . $this->data['xhprof'] . '&source='.$this->data['source'];
169
        }
170
171
        return $this->data['xhprof'];
172
    }
173
174
    /**
175
     * @return \iXHProfRuns
176
     */
177 3
    protected function createRun($serverName, $uri) {
178 3
        $enableXhgui = $this->container->getParameter('jns_xhprof.enable_xhgui');
179 3
        if ($enableXhgui) {
180 2
            $managerRegistry = $this->container->get($this->container->getParameter('jns_xhprof.manager_registry'));
181 2
            $objectManager = $managerRegistry->getManager($this->container->getParameter('jns_xhprof.entity_manager'));
182 2
            if ($objectManager instanceof DocumentManager) {
0 ignored issues
show
Bug introduced by
The class Doctrine\ODM\MongoDB\DocumentManager does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
183 1
                $xhprof_runs = new XhguiRuns_Document($objectManager);
184 1
            } else {
185 1
                $xhprof_runs = new XhguiRuns_Entity($serverName, $uri);
186 1
                $xhprof_runs->setContainer($this->container);
187
            }
188 2
        } else {
189 1
            $xhprof_runs = new \XHProfRuns_Default();
190
        }
191 3
        return $xhprof_runs;
192
    }
193
194
    /**
195
     * Sanitize an uri to use it as source
196
     *
197
     * @param  string $uri
198
     * @return string
199
     */
200
    private function sanitizeUriForSource($uri)
201
    {
202
        $uri = preg_replace('/[\/]+/', '~', $uri);
203
204
        return preg_replace('/[^\w~\-_]+/', '-', $uri);
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210
    public function getName()
211
    {
212
        return 'xhprof';
213
    }
214
215
    /**
216
     * Gets the XHProf extension exists or not.
217
     *
218
     * @return boolean Extension exists or not
219
     */
220
    public function getXhprofExtensionExists()
221
    {
222
        return $this->data['xhprof_extension_exists'];
223
    }
224
225
    /**
226
     * Gets the run id.
227
     *
228
     * @return integer The run id
229
     */
230
    public function getXhprof()
231
    {
232
        return $this->data['xhprof'];
233
    }
234
235
    /**
236
     * Gets the XHProf url.
237
     *
238
     * @return string The XHProf url
239
     */
240
    public function getXhprofUrl()
241
    {
242
        return $this->data['xhprof_url'];
243
    }
244
245
    /**
246
     * Check whether this request was profiled. Used for the debug toolbar.
247
     *
248
     * @return boolean
249
     */
250
    public function isProfiling()
251
    {
252
        return $this->data['xhprof']  ? true : false;
253
    }
254
}
255