Completed
Push — master ( 889dc9...563ddb )
by Jacob
06:44
created

PhpQuickProfiler::setDisplay()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
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
class PhpQuickProfiler
16
{
17
18
    /** @var  integer */
19
    protected $startTime;
20
21
    /** @var  Console */
22
    protected $console;
23
24
    /** @var  Display */
25
    protected $display;
26
27
    /** @var  array */
28
    protected $profiledQueries = array();
29
30
    /**
31
     * @param integer $startTime
32
     */
33
    public function __construct($startTime = null)
34
    {
35
        if (is_null($startTime)) {
36
            $startTime = microtime(true);
37
        }
38
        $this->startTime = $startTime;
0 ignored issues
show
Documentation Bug introduced by
It seems like $startTime can also be of type double. However, the property $startTime is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
39
    }
40
41
    /**
42
     * @param Console $console
43
     */
44
    public function setConsole(Console $console)
45
    {
46
        $this->console = $console;
47
    }
48
49
    /**
50
     * @param Display $display
51
     */
52
    public function setDisplay(Display $display)
53
    {
54
        $this->display = $display;
55
    }
56
57
    /**
58
     * Get data about files loaded for the application to current point
59
     *
60
     * @returns array
61
     */
62
    public function gatherFileData()
63
    {
64
        $files = get_included_files();
65
        $data = array();
66
        foreach ($files as $file) {
67
            array_push($data, array(
68
                'name' => $file,
69
                'size' => filesize($file)
70
            ));
71
        }
72
        return $data;
73
    }
74
75
    /**
76
     * Get data about memory usage of the application
77
     *
78
     * @returns array
79
     */
80
    public function gatherMemoryData()
81
    {
82
        $usedMemory = memory_get_peak_usage();
83
        $allowedMemory = ini_get('memory_limit');
84
        return array(
85
            'used'    => $usedMemory,
86
            'allowed' => $allowedMemory
87
        );
88
    }
89
90
    /**
91
     * @param array $profiled_queries
0 ignored issues
show
Documentation introduced by
There is no parameter named $profiled_queries. Did you maybe mean $profiledQueries?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
92
     */
93
    public function setProfiledQueries(array $profiledQueries)
94
    {
95
        $this->profiledQueries = $profiledQueries;
96
    }
97
98
    /**
99
     * Get data about sql usage of the application
100
     *
101
     * @param object $db
102
     * @returns array
103
     */
104
    public function gatherQueryData($db)
105
    {
106
        if (
107
            empty($this->profiledQueries) &&
108
            property_exists($db, 'queries')
109
        ) {
110
            $this->setProfiledQueries($db->queries);
111
        }
112
113
        $data = array();
114
        foreach ($this->profiledQueries as $query) {
115
            if ($query['function'] !== 'perform') {
116
                continue;
117
            }
118
119
            array_push($data, array(
120
                'sql'     => $query['statement'],
121
                'explain' => $this->explainQuery($query['statement'], $query['bind_values']),
122
                'time'    => $query['duration']
123
            ));
124
        }
125
        return $data;
126
    }
127
128
    /**
129
     * Attempts to explain a query
130
     *
131
     * @param string $query
132
     * @param array  $parameters
133
     * @return array
134
     */
135
    protected function explainQuery($query, $parameters)
136
    {
137
        $query = "EXPLAIN {$query}";
138
        try {
139
            $statement = $this->db->prepare($query);
0 ignored issues
show
Bug introduced by
The property db does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
140
            $statement->execute($parameters);
141
            return $statement->fetch(\PDO::FETCH_ASSOC);
142
        } catch (\Exception $e) {
143
            echo $e->getMessage();
144
        }
145
        return '';
0 ignored issues
show
Bug Best Practice introduced by
The return type of return ''; (string) is incompatible with the return type documented by Particletree\Pqp\PhpQuickProfiler::explainQuery of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
146
    }
147
148
    /**
149
     * Get data about speed of the application
150
     *
151
     * @returns array
152
     */
153
    public function gatherSpeedData()
154
    {
155
        $elapsedTime = microtime(true) - $this->startTime;
156
        $allowedTime = ini_get('max_execution_time');
157
        return array(
158
            'elapsed' => $elapsedTime,
159
            'allowed' => $allowedTime
160
        );
161
    }
162
163
    /**
164
     * Triggers end display of the profiling data
165
     *
166
     * @param object $db
167
     */
168
    public function display($db = null)
169
    {
170
        if (!isset($this->display)) {
171
            throw new Exception('Display object has not been injected into Profiler');
172
        }
173
174
        $this->display->setConsole($this->console);
175
        $this->display->setFileData($this->gatherFileData());
176
        $this->display->setMemoryData($this->gatherMemoryData());
177
        $this->display->setQueryData($this->gatherQueryData($db));
0 ignored issues
show
Bug introduced by
It seems like $db defined by parameter $db on line 168 can also be of type null; however, Particletree\Pqp\PhpQuic...iler::gatherQueryData() does only seem to accept object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
178
        $this->display->setSpeedData($this->gatherSpeedData());
179
180
        $display();
0 ignored issues
show
Bug introduced by
The variable $display does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
181
    }
182
}
183