PhpQuickProfiler::gatherQueryData()   B
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 1 Features 5
Metric Value
c 9
b 1
f 5
dl 0
loc 20
rs 8.8571
cc 5
eloc 12
nc 5
nop 1
1
<?php
2
3
/*****************************************
4
 * Title : PHP Quick Profiler Class
5
 * Author : Created by Ryan Campbell
6
 * URL : http://particletree.com/features/php-quick-profiler/
7
 * Description : This class processes the logs and organizes the data
8
 *  for output to the browser. Initialize this class with a start time
9
 *  at the beginning of your code, and then call the display method when
10
 *  your code is terminating.
11
*****************************************/
12
13
namespace Particletree\Pqp;
14
15
use Exception;
16
17
class PhpQuickProfiler
18
{
19
20
    /** @var  double */
21
    protected $startTime;
22
23
    /** @var  Console */
24
    protected $console;
25
26
    /** @var  Display */
27
    protected $display;
28
29
    /** @var  array */
30
    protected $profiledQueries = array();
31
32
    /**
33
     * @param double $startTime
34
     */
35
    public function __construct($startTime = null)
36
    {
37
        if (is_null($startTime)) {
38
            $startTime = microtime(true);
39
        }
40
        $this->startTime = $startTime;
41
    }
42
43
    /**
44
     * @param Console $console
45
     */
46
    public function setConsole(Console $console)
47
    {
48
        $this->console = $console;
49
    }
50
51
    /**
52
     * @param Display $display
53
     */
54
    public function setDisplay(Display $display)
55
    {
56
        $this->display = $display;
57
    }
58
59
    /**
60
     * Get data about files loaded for the application to current point
61
     *
62
     * @returns array
63
     */
64
    public function gatherFileData()
65
    {
66
        $files = get_included_files();
67
        $data = array();
68
        foreach ($files as $file) {
69
            array_push($data, array(
70
                'name' => $file,
71
                'size' => filesize($file)
72
            ));
73
        }
74
        return $data;
75
    }
76
77
    /**
78
     * Get data about memory usage of the application
79
     *
80
     * @returns array
81
     */
82
    public function gatherMemoryData()
83
    {
84
        $usedMemory = memory_get_peak_usage();
85
        $allowedMemory = ini_get('memory_limit');
86
        return array(
87
            'used'    => $usedMemory,
88
            'allowed' => $allowedMemory
89
        );
90
    }
91
92
    /**
93
     * @param array $profiledQueries
94
     */
95
    public function setProfiledQueries(array $profiledQueries)
96
    {
97
        $this->profiledQueries = $profiledQueries;
98
    }
99
100
    /**
101
     * Get data about sql usage of the application
102
     *
103
     * @param object $dbConnection
104
     * @returns array
105
     */
106
    public function gatherQueryData($dbConnection = null)
107
    {
108
        if (is_null($dbConnection)) {
109
            return array();
110
        }
111
112
        if (empty($this->profiledQueries) && property_exists($dbConnection, 'queries')) {
113
            $this->setProfiledQueries($dbConnection->queries);
114
        }
115
116
        $data = array();
117
        foreach ($this->profiledQueries as $query) {
118
            array_push($data, array(
119
                'sql'     => $query['sql'],
120
                'explain' => $this->explainQuery($dbConnection, $query['sql'], $query['parameters']),
121
                'time'    => $query['time']
122
            ));
123
        }
124
        return $data;
125
    }
126
127
    /**
128
     * Attempts to explain a query
129
     *
130
     * @param object $dbConnection
131
     * @param string $query
132
     * @param array  $parameters
133
     * @throws Exception
134
     * @return array
135
     */
136
    protected function explainQuery($dbConnection, $query, $parameters = array())
137
    {
138
        $driver = $dbConnection->getAttribute(\PDO::ATTR_DRIVER_NAME);
139
        $query = $this->getExplainQuery($query, $driver);
140
        $statement = $dbConnection->prepare($query);
141
        if ($statement === false) {
142
            throw new Exception('Invalid query passed to explainQuery method');
143
        }
144
        $statement->execute($parameters);
145
        $result = $statement->fetch(\PDO::FETCH_ASSOC);
146
        if ($result === false) {
147
            throw new Exception('Query could not be explained with given parameters');
148
        }
149
        return $result;
150
    }
151
152
    /**
153
     * Attempts to figure out what kind of explain query format the db wants
154
     *
155
     * @param string $query
156
     * @param string $driver
157
     * @throws Exception
158
     * @return string
159
     */
160
    protected function getExplainQuery($query, $driver)
161
    {
162
        if ($driver == 'mysql') {
163
            return "EXPLAIN {$query}";
164
        } elseif ($driver == 'sqlite') {
165
            return "EXPLAIN QUERY PLAN {$query}";
166
        }
167
        throw new Exception('Could not process db driver');
168
    }
169
170
    /**
171
     * Get data about speed of the application
172
     *
173
     * @returns array
174
     */
175
    public function gatherSpeedData()
176
    {
177
        $elapsedTime = microtime(true) - $this->startTime;
178
        $elapsedTime = round($elapsedTime, 3);
179
        $allowedTime = ini_get('max_execution_time');
180
        return array(
181
            'elapsed' => $elapsedTime,
182
            'allowed' => $allowedTime
183
        );
184
    }
185
186
    /**
187
     * Triggers end display of the profiling data
188
     *
189
     * @param object $dbConnection
190
     * @throws Exception
191
     */
192
    public function display($dbConnection = null)
193
    {
194
        if (!isset($this->display)) {
195
            throw new Exception('Display object has not been injected into Profiler');
196
        }
197
        if (!isset($this->console)) {
198
            throw new Exception('Console object has not been injected into Profiler');
199
        }
200
201
        $this->display->setStartTime($this->startTime);
202
        $this->display->setConsole($this->console);
203
        $this->display->setFileData($this->gatherFileData());
204
        $this->display->setMemoryData($this->gatherMemoryData());
205
        $this->display->setQueryData($this->gatherQueryData($dbConnection));
206
        $this->display->setSpeedData($this->gatherSpeedData());
207
208
        $this->display->__invoke();
209
    }
210
}
211