Completed
Push — develop ( 682a70...91eb81 )
by Timothy
01:28
created

src/Drivers/Firebird/Result.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php declare(strict_types=1);
2
/**
3
 * Query
4
 *
5
 * SQL Query Builder / Database Abstraction Layer
6
 *
7
 * PHP version 7.1
8
 *
9
 * @package     Query
10
 * @author      Timothy J. Warren <[email protected]>
11
 * @copyright   2012 - 2018 Timothy J. Warren
12
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @link        https://git.timshomepage.net/aviat4ion/Query
14
 */
15
namespace Query\Drivers\Firebird;
16
17
use PDOStatement;
18
use Query\Drivers\PDOStatementInterface;
19
20
/**
21
 * Firebird result class to emulate PDOStatement Class - only implements
22
 * data-fetching methods
23
 *
24
 * @package Query
25
 * @subpackage Drivers
26
 */
27
class Result extends PDOStatement implements PDOStatementInterface {
28
29
	/**
30
	 * Reference to fbird resource
31
	 *
32
	 * @var resource
33
	 */
34
	private $statement;
35
36
	/**
37
	 * Current row in result array
38
	 *
39
	 * @var integer
40
	 */
41
	private $row;
42
43
	/**
44
	 * Data pulled from query
45
	 *
46
	 * @var mixed
47
	 */
48
	private $result = [];
49
50
	/**
51
	 * Reference to the db drive to de-duplicate error functions
52
	 *
53
	 * @var Driver
54
	 */
55
	private $db;
56
57
	/**
58
	 * Create the object by passing the resource for
59
	 * the query
60
	 *
61
	 * @param resource $link
62
	 * @param Driver|null $db
63
	 */
64
	public function __construct($link, Driver $db = NULL)
65
	{
66
		if ( ! is_null($db))
67
		{
68
			$this->db = $db;
69
		}
70
		$this->statement = $link;
71
		$this->setFetchMode(\PDO::FETCH_ASSOC);
72
		$this->row = -1;
73
		$this->result = [];
74
75
		// Create the result array, so that we can get row counts
76
		// Check the resource type, because prepared statements are "interbase query"
77
		// but we only want "interbase result" types when attempting to fetch data
78
		if (\is_resource($link) && \get_resource_type($link) === "interbase result")
79
		{
80
			while($row = \fbird_fetch_assoc($link, \IBASE_FETCH_BLOBS))
81
			{
82
				$this->result[] = $row;
83
			}
84
85
			// Free the result resource
86
			\fbird_free_result($link);
87
		}
88
	}
89
90
	/**
91
	 * Invalidate method for data consistency
92
	 *
93
	 * @param mixed $column
94
	 * @param mixed $param
95
	 * @param int $type
96
	 * @param mixed $maxlen
97
	 * @param array $driverdata
98
	 * @return NULL
99
	 */
100
	public function bindColumn($column, &$param, $type=NULL, $maxlen=NULL, $driverdata=NULL)
101
	{
102
		return NULL;
103
	}
104
105
	/**
106
	 * Invalidate method for data consistency
107
	 *
108
	 * @param mixed $parameter
109
	 * @param mixed $variable
110
	 * @param int $dataType
111
	 * @param mixed $maxlen
112
	 * @param array $driverdata
113
	 * @return NULL
114
	 */
115
	public function bindParam($parameter, &$variable, $dataType=NULL, $maxlen=NULL, $driverdata=NULL)
116
	{
117
		return NULL;
118
	}
119
120
	/**
121
	 * Invalidate method for data consistency
122
	 *
123
	 * @param mixed $parameter
124
	 * @param mixed $variable
125
	 * @param int $dataType
126
	 * @return NULL
127
	 */
128
	public function bindValue($parameter, $variable, $dataType=NULL)
129
	{
130
		return NULL;
131
	}
132
133
	/**
134
	 * Run a prepared statement query
135
	 *
136
	 * @param  array $boundInputParams
137
	 * @return Result
138
	 */
139
	public function execute($boundInputParams = NULL)
140
	{
141
		//Add the prepared statement as the first parameter
142
		\array_unshift($boundInputParams, $this->statement);
143
144
		// Let php do all the hard stuff in converting
145
		// the array of arguments into a list of arguments
146
		// Then pass the resource to the constructor
147
		$this->__construct(\call_user_func_array('fbird_execute', $boundInputParams));
148
149
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Query\Drivers\Firebird\Result) is incompatible with the return type declared by the interface Query\Drivers\PDOStatementInterface::execute of type boolean.

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...
150
	}
151
152
	/**
153
	 * Emulate PDO fetch public function
154
	 *
155
	 * @param int $fetchStyle
156
	 * @param mixed $cursorOrientation
157
	 * @param mixed $cursorOffset
158
	 * @return mixed
159
	 */
160
	public function fetch($fetchStyle=\PDO::FETCH_ASSOC, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset=NULL)
161
	{
162
		// If there is no result, continue
163
		if (empty($this->result))
164
		{
165
			return NULL;
166
		}
167
168
		// Keep track of the current row being fetched
169
		++$this->row;
170
171
		// return NULL if the next row doesn't exist
172
		if ( ! isset($this->result[$this->row]))
173
		{
174
			return NULL;
175
		}
176
177
		switch($fetchStyle)
178
		{
179
			case \PDO::FETCH_OBJ:
180
				$row = (object) $this->result[$this->row];
181
			break;
182
183
			case \PDO::FETCH_NUM:
184
				$row = \array_values($this->result[$this->row]);
185
			break;
186
187
			default:
188
				$row = $this->result[$this->row];
189
			break;
190
		}
191
192
		return $row;
193
	}
194
195
	/**
196
	 * Emulate PDO fetchAll public function
197
	 *
198
	 * @param int  $fetchStyle
199
	 * @param mixed $statement
200
	 * @param mixed $ctorArgs
201
	 * @return mixed
202
	 */
203
	public function fetchAll($fetchStyle=\PDO::FETCH_ASSOC, $statement=NULL, $ctorArgs=NULL)
204
	{
205
		$all = [];
206
207
		while($row = $this->fetch($fetchStyle, $statement))
208
		{
209
			$all[] = $row;
210
		}
211
212
		$this->result = $all;
213
214
		return $all;
215
	}
216
217
	/**
218
	 * Emulate PDOStatement::fetchColumn
219
	 *
220
	 * @param int $columnNum
221
	 * @return mixed
222
	 */
223
	public function fetchColumn($columnNum=0)
224
	{
225
		$row = $this->fetch(\PDO::FETCH_NUM);
226
		return $row[$columnNum];
227
	}
228
229
	/**
230
	 * Emulate PDOStatement::fetchObject, but only for the default use
231
	 *
232
	 * @param string $className
233
	 * @param array|null $ctorArgs
234
	 * @return object
235
	 */
236
	public function fetchObject($className='stdClass', $ctorArgs=NULL)
237
	{
238
		return $this->fetch(\PDO::FETCH_OBJ);
239
	}
240
241
	/**
242
	 * Return the number of rows affected by the previous query
243
	 *
244
	 * @return int
245
	 */
246
	public function rowCount()
247
	{
248
		return \fbird_affected_rows();
249
	}
250
251
	/**
252
	 * Method to emulate PDOStatement->errorCode
253
	 *
254
	 * @return string
255
	 */
256
	public function errorCode()
257
	{
258
		return $this->db->errorCode();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->db->errorCode(); (array) is incompatible with the return type declared by the interface Query\Drivers\PDOStatementInterface::errorCode of type string.

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...
259
	}
260
261
	/**
262
	 * Method to emulate PDO->errorInfo / PDOStatement->errorInfo
263
	 *
264
	 * @return array
265
	 */
266
	public function errorInfo()
267
	{
268
		return $this->db->errorInfo();
269
	}
270
}