I need to get data in PHP from PDO with some transformations of data during the fly. The best variants are FETCH_CLASS mode and FETCH_FUNC mode.
but the problem of FETCH_CLASS is that each property need to go throw __set() method to get transformation or at least to check if it needs transformation. And for 40K rows with 50 columns each it takes too much time.
FETCH_FUNC seems ideal for me cause i get all the columns of the row at once, can make some transforms BUT, the only problem is that i don't have column names cause column values come into function as parameters and the only way to get them is to call func_get_args().
So generally the question is -> How can i get row data at once in some method of the class, function, using some combination of PDO FETCH modes as an assoc array, obj or some like columnName->columnValue structure? Using foreach after getting result is to long - i want to get transformed data already after calling pdo's fetchAll() method
Seems to me like you're overthinking this and are trying to be too clever. This will do just fine:
$data = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$data[] = myTransformation($row);
}
In other words, just fetch with FETCH_ASSOC, then call your function on that result.
Related
I've set up a class to handle my MySQLi calls. The calls are working as they should, so no problems there.
I recently removed the result handling from my class's query method to two separate setter methods. There is now an error resulting from two consecutive fetch_all calls.
The previous (working) code with a single fetch_all call loads results into the two arrays res_rows and res_cols:
// Convert results into two sets of values
// and store in properties
// $res_rows=results by row (column names in element 0)
// Each row is an indexed array
// $res_cols=results by column (associative arrays)
// Key is the column name; Value is an array
$results=$res->fetch_all(MYSQLI_ASSOC);
// $colNames is an array of the column names
$colNames=array_keys($results[0]);
// Rows
foreach($results as $r) {
$this->res_rows[]=array_values($r);
}
array_unshift($this->res_rows,$colNames);
// Columns
$vals=array();
// Count the number columns in the query
$numCols=count($colNames);
// Iterate through the columns
for($i=0;$i<$numCols;$i++) {
$col=$colNames[i];
$storage=array();
foreach($results as $r) {
$storage[]=$r[$colNames[$i]];
}
$vals[]=$storage;
}
$this->res_cols=array_combine($colNames,$vals);
I've moved this code into two methods setRes_rows and setRes_cols and called them sequentially (see code). Each method pulls results from the result object using fetch all.
$this->setRes_rows($res);
$this->setRes_cols($res);
What happens is that the first call behaves as expected, and the second call returns an empty array.
If I reverse the calls (e.g. setRes_cols first), the same thing happens (first call works as expected; second call is empty). So I know the code is good. I even changed all the variable names in one of the methods with no effect.
I dumped all properties and methods on the result object between calls and it doesn't look like it changes. But for some reason that second fetch_all does not work.
The easy fix is for me to use a single fetch_all then call my methods. But I'm interested in knowing if there's anything weird I'm missing.
Thanks, everyone.
It looks like you need to reset the result pointer after a fetch_all.
I didn't find anything in the docs specifically for fetch_all - only about resetting after a fetch_assoc(), where we can find a reference to data_seek(): http://php.net/manual/en/mysqli-result.data-seek.php
So here's what you should do:
before the second fetch_all() do a
$res->data_seek(0); // where $res is your mysqli result Object
This basicly sets the result pointer to the first record.
The answer might be write two functions! However, maybe a little knowledge that I do not have will help avoid a heck of a lot of re-factoring or database usage.
I have a function with the very common syntax of:
while($row = $db->sql_fetchrow($result)) {
// do some stuff
}
Most of the time, the $row will be a mysql object with zero, one or more rows therein. Simple.
However, it would be very handy if I could also utilise a three dimensional PHP array (previously built to be a bunch of "rows" with three key & value pairs) without handling them differently.
The question I have is "What do I need to do to a 3D array to "convert" it to a mysql object that will work without change in the above example"?
There isn't a way to convert into a mysql object without writing to a tmp table and reading it back in. The following will deal with either sql statement or array turning up which then negates the need to convert as the question asked.
$all_rows = $notify->notification_sql(); // This either returns an SQL statement ready to run OR a set of rows in an array
if (!is_array($all_rows)) { // If it's not an array, run the SQL query and put it into an array of rows
$result = $db->sql_query($all_rows);
$all_rows = array();
while($row = mysql_fetch_array($result)) {
$all_rows[] = $row;
}
}
foreach...
This question already has answers here:
How do I make sure that values from MySQL keep their type in PHP?
(5 answers)
Closed 1 year ago.
I'm using custom PHP wrapper for for mysqli. The class is designed to use prepared statements if bind parameters are passed to the a fetchResultSet function otherwise, as is my understanding, it saves a call to the database and uses the query function (perhaps I'm wrong saving a call and the rest of this question can be answered by simply using prepared statements even with no parameters to bind).
Once the query has been executed a fetchResult function passes back one of two objects ResultSetObjectResult or ResultSetObjectStmt both of witch implement a ResultSetObject interface. (The ResultSetObjectStmt object wraps an stmt object while the ResultSetObjectResult wraps a result object.)
Both classes return an associative array when a row is requested either though calling fetch_assoc on a result or calling bind_result on an stmt object (basically).
What I've noticed is that if a prepared statement is executed then the data returned are properly casted to integers, real numbers and strings depending on their types in the database; but when a result is returned and fetch_assoc is called on that result then all of the data are casted as strings. I realize this is mentioned in the documentation for fetch_assoc. I'm curious if there is another function or something I can do to have mysql properly cast the results.
[EDIT]
I should mention that this is only an issue because json_encode places data in quotes depending on their types.
[EDIT AGAIN]
I like to know if there is anyway to properly cast the data returned from a result without resorting to guess work using functions like is_numeric or by making an additional call to the database for the schema of the table. Using prepared statements exclusively when fetching data works, but I'd really love to save that additional prepare call to the database.
I don't know what wrapper your using but you could have a function like...
while ($row = $query->fetch_assoc()) {
$row = auto_cast($row);
}
function auto_cast($row) {
foreach ($row as $key => $value) {
if (ctype_digit($value)) {
$row[$key] = (int) $value;
}
elseif (is_numeric($value)) {
$row[$key] = (float) $value;
}
else {
$row[$key] = (string) $value;
}
}
return $row;
}
I will try to help here. When usign prepared statement, the PHP knows what is the column type and depending on that stores data in different types: string, integer, bool, etc. When using fetch_assoc it does not know this info. You could create a function that is getting the fields/columns MySQL data using mysqli_fetch_fields and use their type. Based on that you could typecast them. Hope that will help.
Fior information about different column types see here http://www.php.net/manual/en/mysqli.constants.php
MYSQLI_TYPE_LONG - Field is defined as INT an so on.
I am confused about this, I run a query such as
foreach($dbh->query("SELECT * FROM ...") as $row) {
...do something with row()
But when I var_dump $dbh it is a PDOstatement object.
This leads me to two questions:
How does foreach somehow resolve the object into separate rows?
How can I store all rows in an array, like $arr = $dbh->query(...)? This does not work because it is still an object
I can of course run under the foreach, and do $arr[] = $row, but that seems a bit silly..
PHP has some interesting interfaces that let you handle objects as arrays. In this case the PDOStatement class implements Traversable and this allows the use of foreach on it. See here http://www.php.net/manual/en/class.pdostatement.php
To get all your results in one array take a look at PDOStatement::fetchAll. And also in the future consider checking the PHP documentation on php.net if you run into problems. It's packed with examples and useful user comments.
Use PDOStatement::fetchAll() to get the entire result set as array. AS far as what PDO does internally it uses an iterator to access some representation of a recordset. This way you use less memory because youre not pulling the entire result set into php, youre using something resembling a resource thats internal to the implementation.
I'm a .net programmer vb & c#, but I can't seem to figure out how to get my objects into a list or array in PHP.
var mylist = new List<myobject>();
mylist.add(myobject1);
mylist.add(myobject2);
What I have tried.
Products being a property for a collection of orderitems:
$this->Products = getOrderItems();
public function getOrderItems()
{
$items = array();
$count = 0;
// connect to db, query.....
while($row = mysql_fetch_array($result, MYSQL_BOTH)){
$count++;
$items[$count] = ($row);
}
echo 'Count of Order Items...' . $count;
return $items;
}
Am I even close?
$items = array();
while($row = mysql_fetch_array($result, MYSQL_BOTH)) {
$items[] = $row;
}
echo 'Count of Order Items...', count($items);
$this->Products = getOrderItems(); is legal in PHP, but it refers to the (global) function getOrderItems() instead of the class method. class methods and variables always have to be prefixed with $this-> (or self::, if they're static vars) when called from inside the class.
in your sample-code, you have that wrong. getOrderItems is defined as class method, but your call is not $this->-scoped, thus php assumes a function. it should throw an function not found-error.
the [] notation adds an element to the end of an array.
the index of the first element in your sample code is 1 (isn't that the standard case for VB?). php normally starts at 0 - though it's possible (because php-arrays are not real arrays) to start at arbitrary indices i'd recommend to stick with zero.
mysql_fetch_array is an ancient way of working with mysql. nowadays you're better of with mysqli or (even better) PDO.
(...) a list or array in php.
lists, arrays, stacks, whatever: in php everthing is an ordered map (misleadingly called array):
PHP: Arrays: An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.
update:
sorry, i haven't got enough time right now to explain the finer nuances of pdo/mysqli over mysql.
so here are just the basics:
oop: pdo and mysqli are object oriented (tough mysqli got functional aliases)
prep statements: most important: pdo/mysqli got prepared statements. that means, you first prepare the query with placeholders once, then fill in the values later (without the need to prepare the query a second time). this approach has 3 obvious advantages:
performance: it's faster, because the database only has to analyze, compile and optimize the query once (at least with complex queries)
security: no need for quoted strings (happens automatically!), making sql-injection attacks harder
maintainability: the logic and data part of the query are separated, thus easier to read and you don't have to do a lot of string concenation
driver driven: pdo is not database specific. there are several supported db-systems, making it easier to port your code to other db-backends (but it's not an db-abstraction layer like ODBC, so the SQL still has to be compatible) and increasing reusability
of course, there's a lot more to it
What orlandu63 posted is correct - using $items[] = $row means that $row is appended numerically as the next element of $items.
Another option is that if there's an id field in $row, you can do $items[$row->id] = $row;, which has the advantage of indexing your array and making it easier to find a given item.
I really suggest reading through http://www.php.net/manual/en/language.types.array.php, which will explain to you some of the cool things PHP allows with arrays.