Which one of the options below is better
Option 1:
//control file:
$smpt = $con->query("SELECT id,name FROM customers");
//fetch all resuts
$results = array();
while ($row = $result->fetch_assoc()) {
$results[] = $row;
}
$smpt->close();
//Note: PHP version < 5.3.0 so I can't use just $results->fetch_all('MYSQLI_ASSOC');
//view file:
foreach($results as $key=>$value) {
//display results
}
unset($results);
Option 2:
//control file:
$smpt = $con->query("SELECT id,name FROM customers");
//fetch all resluts
//view file:
while($row = $result->fetch_assoc()) {
//display results
}
$smpt->close();
I am trying to completely separate the logic from presentation... Current I am using option 2 because with option 1 the script go through 2 loops. one to fetch data and the other to display them. But which one is better to use?
Thanks
Option 1 allows you to re-use the $data variable so you can display the results twice, but the cost of this is that you potentially have a large amount of data stored in a variable. You can clear this by using unset($data) once you are 100% sure you've finished with it.
Option 2 requires less loops (only one instead of two) and doesn't need a extra variable to store the data. The cost of this is that the while loop can only be used once.
In the grand scheme of things, the differences in speed will be so minimal the user won't notice them, however if there are 20+ instances of this in once script then it could have a noticeable affect.
I would recommend Option 2 providing that you'd only need to use the while loop once. Also, you could benchmark your scripts to see how they perform against one another.
It's always best that views only deal with presentation concerns.
So between the two options you've mentioned, I'd choose option 1 so you don't have to close $smpt inside the view ($smpt has nothing to do with the presentation layer).
Related
I'm revamping the packaging screen in our inventory system. The user opens a package and inserts/removes the items in it, and when he presses Save, a json array of all the parts that are in the package is sent to a PHP endpoint which takes care of saving the package in the database.
So far everything is good, I have created my functions to send data between PHP and javascript. However, even though the json array that javascript sends to PHP contains all the info on the products (as javascript needed to retrieve it anyway to fill in the grid in the gui), I still have to validate everything in PHP because I can't be sure that the user didn't tampered with the data from the console before trying to save.
With that said, in PHP, I receive the json array, which I use the IDs to load a list of proper objects into an array. I'm doing this:
$in = str_repeat('?,', count($itemIDs) - 1) . '?';
$sql = "SELECT * FROM tbProduct WHERE nID IN ($in)";
$sttmt = $db->prepare($sql);
$sttmt->execute($itemIDs);
$res = $sttmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $key => $productInfo) {
$prod = new tbProduct($db);
$prod->loadFromArray($productInfo);
}
so far so good, I now have an array of tbProduct, which is my class for the products.
What I now have to do is run a validation on this array of objects to make sure all these objets are in the proper status to be packaged together. These validations include making sure all the products have the same status, that none of the products are assembly parts, that all the products have the same owner, etc. This way, even if the array was tampered with in the browser's console, I'll be sure to use the information from the DB anyway.
So I need a way to validate this. I could just do a foreach, store everything that needs to be checked from the very first item in variables, and just compare each subsequent item to these variables, but I'm sure there are better ways to do this. I need something that will be as efficient as possible. My packages can(and will) contain several hundreds of products, so the solution needs to be fast.
What would be the best way of doing this?
Thank you!
You can do it during the loop that's processing all the data returned by the query. Set a variable to the first object, then you can compare other elements to it.
$res = $sttmt->fetchAll(PDO::FETCH_ASSOC);
$firstprod = new tbProduct($db);
$firstprod->loadFromArray(array_shift($res));
foreach ($res as $key => $productInfo) {
$prod = new tbProduct($db);
$prod->loadFromArray($productInfo);
if ($prod->status != $firstprod->status) {
// report inconsistent status
} elseif ($prod->owner != $firstprod->owner) {
// report inconsistent owner
} elseif ($prod->type != "assembly") {
// report that it must ba an assembly part
} ...
}
I have finished writing my php scripts for a project I am doing. My next step is I would like to see if I can improve my code from a memory stand point as some of my scripts eat a lot of memory. I have been doing research on this and one suggestion is to NULL and unset variables, but I never see an example of doing this. So I wanted to give an example of a common action done in my scripts and wanted to know if this is the proper way of doing this:
$query = $dbconn->get_results("SELECT id,name FROM account WHERE active = 1");
if(isset($query))
{
foreach($query AS $currq)
{
$account_id = intval($currq->id);
$account_name = trim($currq->name);
//Code to stuff with this data
//NULL the variables before looping again
$account_id = NULL;
$account_name = NULL;
//Unset the variables before looping again
unset($account_id);
unset($account_name);
}
$query = NULL;
unset($query);
$currq = NULL;
unset($currq);
Would that be the correct way to free up memory? I read the garbage collection in PHP can be lazy, so that is why they recommend to NULL the value as it will shrink it right away.
I know this might be too vague for this site, but if anyone can just let me know if this is the proper way of freeing up memory? Or if there is a different way, can you please provide an example just so I can visually see how it work. Thanks in advance!
Please read up on PHP generators, that is what they are exactly for.
You don't want to fetch all records at once, this would blow holes into your memory like a shotgun.
Instead you want to fetch your records one at the time, process it then fetch the next one.
Here is an example:
function getAccountData(\PDO $pdo)
{
$stmt = $pdo->prepare("SELECT id,name FROM account WHERE active = 1");
$stmt->execute();
while ($row = $stmt->fetch()) {
yield $row;
}
}
foreach (getAccountData($pdo) as $account){
//process the record for each iteration
//no need to unset anything
}
Well, if the function $dbconn->get_results returns an array with all the data, then there is no point in using generators since the memory has already being allocated for the data.
You can also use the mysqli_fetch_assoc function to get one row at a time. It should be more memory efficient then fetching all rows at once. http://php.net/manual/en/mysqli-result.fetch-assoc.php
So, I'm learning PHP and MySQL, but I have run into a little problem here.
I do lack some information, so this will be very helpful to me =)
I do a query against my database, and get a result. This result is all my image files to be listed.
$fileSQL = $mysqli->query("
SELECT *
FROM content
WHERE projID=$projectID
");
So, if I want to list all my files as thumbnails on my page I do this:
<?php while($row = $fileSQL->fetch_assoc()){ ?>
<img src="assets/<?=$row['contentFull']?>" id="thumbImg"
onclick="document.getElementById('mainImage').src=this.src" width="110px" height="62px"/>
<?php } ?>
Now, this works fine, of course. It loops through all the rows while adding a for each of them.
However, I do have a main image too, where I need to show the first thumb in full (for this example I use contentFull both for thumbs and fullsize).
Now, how do I get the first row's contentFull, without making the while loop start from row nr.2?
And in general; what is the best way to do in these situations? Store the result to an array first, so I can access it easily, or what is the "normal" way of doing it? =)
What I need:
Do a query
Set the main image (using contentFull from the first
image/content in my sql result)
Then draw all the images in the
result to thumbnails (including the first that are already shown as
the main image)
Thanks in advance, and please let me know if you need more information =)
One simple options would be to do this:
<?php
$first = null;
while($row = $fileSQL->fetch_assoc()) {
if(!isset($first)) $first = $row;
?>
<img src="assets/<?=$row['contentFull']?>" id="thumbImg"
onclick="document.getElementById('mainImage').src=this.src" width="110px" height="62px"/>
<?php } ?>
Now you have the first row stored in a variable to use, without having to store all the results in an array. If for some reason you want all rows stored in an array you could simply do this:
<?php
$rows = array();
while($row = $fileSQL->fetch_assoc()) {
$rows[] = $row;
//rest of code
}
?>
Then you could access first row by referencing $rows[0]
Another option would be to not use php to populate the full image. Instead use a javascript call to populate the first image.
I think you could take your first picture outside the while loop:
$row = $fileSQL->fetch_assoc(); // the first picture
if($row){
// show first image if it exists
}
while ( $row = $fileSQL->fetch_assoc()) // etc.
Probably code for larger image is different than for others, so it could be reasonable. If not, consider defining a function, or use a counter (or flag like in Pitchinnate's answer).
These two pull out data from two different data bases. It's all good undtil I repeat the first one for a second time (to pull out the count of comments of more than one article), the second script (pulls out the data about vistis to the articles and arranges them by desc. order) stops working (no error, nothing, just doesn't provide an output). I'm no expert (yet) in the PHP so I can't seem to figure what is wrong in this sutuation. Maybe some of you will notice some obvious flaw which makes 'em interfere like that?
1st script (comment count). Just to make it clear: I don't use "define", the second time I use it for a diff. article. It's needed just in the first one to work.):
<?php
$id = "1"; //The ID of the page. You can get this from Manage -> Pages.
define('IN_COMMENTICS', '1');
require ($_SERVER['DOCUMENT_ROOT'].'comments/includes/db/connect.php');
$query = mysql_query("SELECT * FROM `".$cmtx_mysql_table_prefix."comments` WHERE is_approved = '1' AND page_id = '$id'");
$total = mysql_num_rows($query);
echo $total;
?>
Second script (counts visits):
<?php
$sql = "SELECT pagename, hits, title FROM counts ORDER BY hits DESC LIMIT 10";
$res = mysql_query($sql);
if(!$res) {
// oops - exit?
}
while(list($page,$hits,$title) = mysql_fetch_row($res)) {
echo "<li><a href='$page'>$title</a> $hits</li>";
}
?>
The only thing I could see is that you are using the function require to include you database initializing file, AND its executed two times which my create problems to causing this issue you are facing.
Perhaps, consider using require_once function which will take care to not load the database initializing file more than one time.
To conclude, I would suggest to do the following
Replace this:
require ($_SERVER['DOCUMENT_ROOT'].'comments/includes/db/connect.php');
by this:
require_once ($_SERVER['DOCUMENT_ROOT'].'comments/includes/db/connect.php');
Is it possible to ask for all data in my database and make objects from it and save it into an array or something, so I just need to call the database once and afterwards I just use my local array? If yes, how is it done?
public function getAllProjects(){
$query="SELECT * FROM projects";
$result=mysql_query($query);
$num=mysql_numrows($result);
while ($row = mysql_fetch_object($result)) {
// save object into array
}
}
public function fetchRow($row){
include("Project.php");
$project = new Project();
$id=$row->id;
$project->setId($id);
$title=$row->title;
$project->setTitle($title);
$infos=$row->info;
$project->setInfo($infos);
$text=$row->text;
$project->setText($text);
$cate=$row->category;
$project->setCategory($cate);
return $project;
}
If I have for example this code. How do i store the objects correctly into an array, where I grab the data from? And why can't I make more than one object of type "Project"?
Let's ignore the fact that you will run out of memory.
If you have everything in an array you will no longer have the functionalities of a relational database.
Try a search over a multi megabytes, multi dimensional array in php and be prepared for a extended coffee break.
If you are thinking in doing something like that is because you feel that the database is slow... You should learn about data normalization and correct use of indexes then.
And no NoSQL is not the answer.
Sorry to pop your balloon.
Edited to add: What you CAN to is use memcache to store the final product of some expensive processes. Don't bother storing the result of trivial queries, the internal cache of mysql is very optimized for those.
You should use the $_SESSION vars in php, To use them, add a session_start() at the beginning of your code. Then you can set vars with $_SESSION['selectaname'] = yourvar
Nothing prevent you to make a sql query like "SELECT username FROM users WHERE id = 1" and then set a $_SESSION['user'] = $queryresult
Then you'll have this :
echo $_SESSION['user'];
"mylogin"