MySQL PDO resultSet as object list performance - php

I'm using the following code to get records from DB:
$stmt->setFetchMode(PDO::FETCH_CLASS, MyClass::class);
$resultSet = $stmt->fetchAll();
return $resultSet;
This works fine.
However sometimes the PHP class property names and the database field names are different. In this case we make a mapping as follows:
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$resultSet = $stmt->fetchAll();
foreach ($resultSet as $record) {
$resultList[] = $this->convertDbArrayToObject($record, MyClass::class, $mapping);
}
return $resultList;
where
public function convertDbArrayToObject($record, $class, $mapping = null)
{
$object = new $class();
foreach ($record as $key => $value) {
if (array_key_exists($key, $mapping)) {
$fieldName = $mapping[$key];
$setterName = 'set' . ucfirst($fieldName);
$object->$setterName($value);
}
}
return $object;
}
The problem is that the second solution is about ~10-20 times slower that is way too much.
Any idea how could we improve the performance?

Related

Returns multiple values from a PHP function

Apologize for the repeated question. Return multiple values from database with function. I tried executing code, the function returns one value, where I want all the values of id and name.
Database: id and name has 9 rows. Is there anything I was missing in my code.
function readdata() {
$sth = $db->execute('SELECT * FROM mynumbers m WHERE m.id>1 ORDER BY m.id ASC');
foreach ($sth as $s) {
$object = new stdClass();
$object->id = $s->id;
$object->name = $s->name;
return $object;
}
}
$rd = readdata();
echo $rd->id;
echo $rd->name;
May be something like this:
function readdata() {
$sth = $db->execute('SELECT * FROM mynumbers m WHERE m.id>1 ORDER BY m.id ASC');
$out = [];
foreach ($sth as $s) {
$object = new stdClass();
$object->id = $s->id;
$object->name = $s->name;
$out[] = $object;
}
return $out;
}
$rd = readdata();
//and here
foreach($rd as $obj){
echo $obj->id;
echo $obj->name;
}
This is more a suggestion than an answer. Why re-inventing the wheel? PDO already is capable of returning classes and also fetching all results into an array.
function readdata(PDO $db): array
{
$sth = $db->prepare('SELECT * FROM mynumbers m WHERE m.id>1 ORDER BY m.id ASC');
$sth->execute();
return $sth->fetchAll(PDO::FETCH_CLASS);
}
$objects = readdata($db);
$objects is now an array. Each element contains a stdClass object with each column name as property.
foreach($objects as $object) {
echo $object->id, PHP_EOL;
echo $object->name, PHP_EOL;
}
Your foreach loop intends to run through all values of the array $sth, but returns only with the FIRST one.
You can just return $sth to get the whole array, or build a new array and append to it:
$ret = array();
foreach ($sth as $s) {
...
$ret[] = $object;
}
and then
return $ret;

Retrieve data with foreach from return array function

I'm having troubles with my function and how to retrieve the data. Here is what i got.
public function getImages()
{
$array = array();
//Test query
$query = $this->connect()->query("SELECT * from user");
while ($row = $query->fetch()) {
$array[] = $row;
return $array;
}
}
Now I'm calling this function but i can not use foreach to access the array.
include "header.html";
include "autoload.php";
spl_autoload_register('my_autoloader');
$users = new User;
$users->getImages();
foreach ($users as $value) {
echo $value["username"];
}
What am I doing wrong? I'm only getting one result but there are many in my database. Or if i call the $array in foreach it says undefined.
A couple things. First, your function is only ever returning an array with one element in it. If you want to finish populating the array, don't return until after the loop:
while ($row = $query->fetch()) {
$array[] = $row;
}
return $array;
And second, you're trying to iterate over the object which has the function, not the value returned from the function. Get the return value and iterate over that:
$userDAO = new User;
$users = $userDAO->getImages();
foreach ($users as $value) {
echo $value["username"];
}
You just need to put the return statement out of the while loop.
public function getImages() {
$array = array(); //Test query
$query = $this->connect()->query("SELECT * from user");
while ($row = $query->fetch()) {
$array[] = $row;
}
return $array;
}

Save multiple records with doctrine and getting id every record

I Have a function in my php application to save data in table:
public function saveAdditionalDataForRecord($header, $data, $record)
{
$em = $this->getEntityManager();
foreach ($header as $key => $value) {
$clientRecordAdditionalData = new ClientRecordAdditionalData();
$clientRecordAdditionalData->setName($value);
$clientRecordAdditionalData->setValue($data[$key]);
$clientRecordAdditionalData->setRecord($record);
$em->persist($clientRecordAdditionalData);
}
$em->flush();
return $clientRecordAdditionalData->getId();
}
I'd like to return array with id saved records instead last saved record. How Can I do that? I would be greateful for help ;)
Best regards
public function saveAdditionalDataForRecord($header, $data, $record)
{
$em = $this->getEntityManager();
$ids = array();
$objects = array();
foreach ($header as $key => $value) {
$clientRecordAdditionalData = new ClientRecordAdditionalData();
$clientRecordAdditionalData->setName($value);
$clientRecordAdditionalData->setValue($data[$key]);
$clientRecordAdditionalData->setRecord($record);
$em->persist($clientRecordAdditionalData);
$objects[] = $clientRecordAdditionalData;
}
$em->flush();
foreach($objects as $object)
{
$ids[] = $object->id;
}
return $ids;
}
There are only two ways to do this: either use non-sequintial IDs (UUIDs) that you generate before inserting or retrieve last insert id after each insert(flush).
Install ramsey/uuid to generate uuid.
foreach ($header as $key => $value) {
$clientRecordAdditionalData = new ClientRecordAdditionalData();
$clientRecordAdditionalData->setId(Uuid::uuid4());
$clientRecordAdditionalData->setName($value);
$clientRecordAdditionalData->setValue($data[$key]);
$clientRecordAdditionalData->setRecord($record);
$em->persist($clientRecordAdditionalData);
}

How to get results from prepared statment without using getresult?

You may think this question is not up to the mark. But i have to post it here... :(
$stmt->get_results
is not working in my hosting server as the mysqlind is not available there.
i have completed my projects without knowing this and its killing me now...
To overcome this i have created the below function and its working fine. As you can see this function is returning array. Now i am trying to create the exact object which $stmt->get_results return. ie i need to use fetch_assoc() with the object. Other wise i have to edit a large number of files that will kill my time :(.. if somebody can help me pls...
private function getMyResult($stmt)
{
$result = array();
$metadata = $stmt->result_metadata();
$data['result']=$metadata; echo "<br/>-------------<br/>1";
/*while ($myrow = $data['result']->fetch_assoc())
{
print_r($myrow);
}*/
$fields = $metadata->fetch_fields();
print_r($metadata);
for (;;)
{
$pointers = array();
$row = new stdClass();
$pointers[] = $stmt;
foreach ($fields as $field)
{
$fieldname = $field->name;
$pointers[] = &$row->$fieldname;
}
call_user_func_array('mysqli_stmt_bind_result', $pointers);
if (!$stmt->fetch())
break;
$result[] = $row;
}
$metadata->free();
return $result;
}

Foreaching PDO bindValue / BindParam

I wanted to make my life a bit easier like in this post:
PDO::bindParam in a foreach loop, all values are being set as the same?
And several others...
I tried several variants to get my code work (to see messages) but no result i have to methods in my class:
public function getMessages($locationId, $name) {
if(!empty($name)) {
$query = 'SELECT * FROM (SELECT * FROM sms WHERE location_id=:locationId ORDER BY id DESC LIMIT 5) AS SOURCE ORDER BY id ASC';
$parameters = array(':locationId' => $locationId);
$row = $this->returnDataObject($query, $parameters);
while ($row) {
$this->fetchData($row, $biggestId, $name);
}
$this->updateSessionKey($locationId, $name);
}
}
And the other:
public function returnDataObject($query, $parameters) {
var_dump($query);
var_dump($parameters);
$dataObject = $this->dbh->prepare($query);
foreach ($parameters as $key => &$value) {
$dataObject->bindParam($key, $value);
}
$dataObject->execute();
$row = $dataObject->fetch(PDO::FETCH_OBJ);
return $row;
}
I tried:
foreach ($parameters as $key => &$value) {
and:
foreach ($parameters as $key => $value) {
I tried:
$dataObject->bindParam($key, $value);
and:
$dataObject->bindValue($key, $value);
I also tried in getMessages method to die('I am in getMessages method');
But i couldn't get that far...
What should i do differently to get this code work?
I appreciate any help!
EDIT:
My bad with biggestId but declaring biggestId:
$biggestId = $this->getBiggestId($locationId);
But fixing that didn't fix the whole problem. This first method works perfictly if it is:
public function getMessages($locationId, $name) {
if(!empty($name)) {
$biggestId = $this->getBiggestId($locationId);
$messages = $this->dbh->prepare('SELECT * FROM (SELECT * FROM sms WHERE location_id=:locationId ORDER BY id DESC LIMIT 5) AS SOURCE ORDER BY id ASC');
$messages->bindParam(':locationId', $locationId);
$messages->execute();
while ($row = $messages->fetch(PDO::FETCH_OBJ)) {
$this->fetchData($row, $biggestId, $name);
}
$_SESSION[$name] = $biggestId;
}
}
But i want to use the method so i don't have to bindParam / BindValue manualy, the functionality of returnDataObject method would make my life easier...
Make the following Changes:
use fetchAll() instead of fetch()
Since fetchAll() is used, use a foreach rather than a while loop.
returnDataObject:
public function returnDataObject($query, $parameters) {
$dataObject = $this->dbh->prepare($query);
foreach ($parameters as $key => &$value) {
$dataObject->bindParam($key, $value);
}
$dataObject->execute();
$rows = $dataObject->fetchAll(PDO::FETCH_OBJ);
return $rows;
}
getMessages:
public function getMessages($locationId, $name) {
if(!empty($name)) {
$query = 'SELECT * FROM (SELECT * FROM sms WHERE location_id=:locationId ORDER BY id DESC LIMIT 5) AS SOURCE ORDER BY id ASC';
$parameters = array(':locationId' => $locationId);
$rows = $this->returnDataObject($query, $parameters);
foreach($rows as $row) {
$this->fetchData($row, $biggestId, $name);
}
$this->updateSessionKey($locationId, $name);
}
}

Categories