Completed
Push — master ( a67fbf...bd980a )
by Nazar
04:05
created

MySQLi   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 72.31%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 203
ccs 94
cts 130
cp 0.7231
rs 8.4864
c 1
b 1
f 0
wmc 48
lcom 2
cbo 1

13 Methods

Rating   Name   Duplication   Size   Complexity  
B get_host_and_port() 0 20 6
B __construct() 0 22 4
B q_internal() 0 17 5
A q_internal_internal() 0 20 4
B f() 0 19 10
A id() 0 3 1
A affected() 0 3 1
A free() 0 6 2
B columns() 0 12 5
A tables() 0 8 4
A s_internal() 0 4 2
A server() 0 3 1
A __destruct() 0 6 3

How to fix   Complexity   

Complex Class

Complex classes like MySQLi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MySQLi, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\DB;
9
use
10
	mysqli_result;
11
12
class MySQLi extends _Abstract {
13
	/**
14
	 * @var \MySQLi Instance of DB connection
15
	 */
16
	protected $instance;
17
	/**
18
	 * @inheritdoc
19
	 */
20 24
	public function __construct ($database, $user = '', $password = '', $host = 'localhost', $prefix = '') {
21 24
		$start = microtime(true);
22
		/**
23
		 * Parsing of $host variable, detecting port and persistent connection
24
		 */
25 24
		list($host, $port) = $this->get_host_and_port($host);
26 24
		$this->instance = new \MySQLi($host, $user, $password, $database, $port);
27 24
		if (!is_object($this->instance) || $this->instance->connect_errno) {
28 1
			return;
29
		}
30 24
		$this->database = $database;
31
		/**
32
		 * Changing DB charset if necessary
33
		 */
34 24
		if ($this->instance->character_set_name() != 'utf8mb4') {
35 24
			$this->instance->set_charset('utf8mb4');
36
		}
37 24
		$this->connected       = true;
38 24
		$this->connecting_time = microtime(true) - $start;
39 24
		$this->db_type         = 'mysql';
40 24
		$this->prefix          = $prefix;
41 24
	}
42
	/**
43
	 * Parse host string into host and port separately
44
	 *
45
	 * Understands `p:` prefix for persistent connections
46
	 *
47
	 * @param string $host_string
48
	 *
49
	 * @return array
50
	 */
51 24
	protected function get_host_and_port ($host_string) {
52 24
		$host = explode(':', $host_string);
53 24
		$port = ini_get('mysqli.default_port') ?: 3306;
54 24
		switch (count($host)) {
55 24
			case 1:
56 24
				$host = $host[0];
57 24
				break;
58 1
			case 2:
59 1
				if ($host[0] == 'p') {
60 1
					$host = "$host[0]:$host[1]";
61
				} else {
62 1
					list($host, $port) = $host;
63
				}
64 1
				break;
65 1
			case 3:
66 1
				$port = $host[2];
67 1
				$host = "$host[0]:$host[1]";
68
		}
69 24
		return [$host, $port];
70
	}
71
	/**
72
	 * @inheritdoc
73
	 *
74
	 * @return bool|mysqli_result
75
	 */
76 24
	protected function q_internal ($query, $parameters = []) {
77 24
		if (!$query) {
78 1
			return false;
79
		}
80 24
		$result = $this->q_internal_internal($query, $parameters);
81
		/*
82
		 * In case of MySQL Client error try once again
83
		 */
84
		if (
85 24
			!$result &&
86 24
			$this->instance->errno >= 2000 &&
87 24
			$this->instance->ping()
88
		) {
89
			$result = $this->q_internal_internal($query, $parameters);
90
		}
91 24
		return $result;
92
	}
93
	/**
94
	 * @param string $query
95
	 * @param array  $parameters
96
	 *
97
	 * @return bool|mysqli_result
98
	 */
99 24
	protected function q_internal_internal ($query, $parameters) {
100 24
		if (!$parameters) {
101 24
			return $this->instance->query($query);
102
		}
103 21
		$stmt = $this->instance->prepare($query);
104 21
		if (!$stmt) {
105
			return false;
106
		}
107
		// Allows to provide more parameters for prepared statements than needed
108 21
		$local_parameters = array_slice($parameters, 0, substr_count($query, '?'));
109 21
		$stmt->bind_param(
110 21
			str_repeat('s', count($local_parameters)),
111 21
			...$local_parameters
112
		);
113 21
		$result = $stmt->execute();
114
		/**
115
		 * Return result only for SELECT queries, boolean otherwise
116
		 */
117 21
		return $stmt->get_result() ?: $result;
118
	}
119
	/**
120
	 * @inheritdoc
121
	 *
122
	 * @param false|mysqli_result $query_result
123
	 */
124 23
	public function f ($query_result, $single_column = false, $array = false, $indexed = false) {
125 23
		if (!($query_result instanceof mysqli_result)) {
126 1
			return false;
127
		}
128 23
		$result_type = $single_column || $indexed ? MYSQLI_NUM : MYSQLI_ASSOC;
129 23
		if ($array) {
130 20
			$result = [];
131 20
			while ($current = $query_result->fetch_array($result_type)) {
132 20
				$result[] = $single_column ? $current[0] : $current;
133
			}
134 20
			$this->free($query_result);
135 20
			return $result;
136
		}
137 22
		$result = $query_result->fetch_array($result_type);
138 22
		if ($result === null) {
139 16
			$result = false;
140
		}
141 22
		return $single_column && $result ? $result[0] : $result;
142
	}
143
	/**
144
	 * @inheritdoc
145
	 */
146 17
	public function id () {
147 17
		return $this->instance->insert_id;
148
	}
149
	/**
150
	 * @inheritdoc
151
	 */
152 1
	public function affected () {
153 1
		return $this->instance->affected_rows;
154
	}
155
	/**
156
	 * @inheritdoc
157
	 *
158
	 * @param false|mysqli_result $query_result
159
	 */
160 20
	public function free ($query_result) {
161 20
		if ($query_result instanceof mysqli_result) {
162 20
			$query_result->free();
163
		}
164 20
		return true;
165
	}
166
	/**
167
	 * @inheritdoc
168
	 */
169 2
	public function columns ($table, $like = false) {
170 2
		if (!$table) {
171 1
			return false;
172
		}
173 2
		if ($like) {
174 1
			$like    = $this->s($like);
175 1
			$columns = $this->qfas("SHOW COLUMNS FROM `$table` LIKE $like") ?: [];
176
		} else {
177 2
			$columns = $this->qfas("SHOW COLUMNS FROM `$table`") ?: [];
178
		}
179 2
		return $columns;
180
	}
181
	/**
182
	 * @inheritdoc
183
	 */
184 1
	public function tables ($like = false) {
185 1
		if ($like) {
186 1
			$like = $this->s($like);
187 1
			return $this->qfas("SHOW TABLES FROM `$this->database` LIKE $like") ?: [];
188
		} else {
189 1
			return $this->qfas("SHOW TABLES FROM `$this->database`") ?: [];
190
		}
191
	}
192
	/**
193
	 * @inheritdoc
194
	 */
195 22
	protected function s_internal ($string, $single_quotes_around) {
196 22
		$return = $this->instance->real_escape_string($string);
197 22
		return $single_quotes_around ? "'$return'" : $return;
198
	}
199
	/**
200
	 * @inheritdoc
201
	 */
202 1
	public function server () {
203 1
		return $this->instance->server_info;
204
	}
205
	/**
206
	 * @inheritdoc
207
	 */
208 2
	public function __destruct () {
209 2
		if ($this->connected && is_object($this->instance)) {
210 2
			$this->instance->close();
211 2
			$this->connected = false;
212
		}
213 2
	}
214
}
215