I have a variable, for example $total1. It has a value from the database, for example 6.
Now I do an SQL query and it gets some numbers from tables. For example this:
$subtraction1=5, but it is in a while loop so the second time it could be $subtraction1=10 or something like that. Every time in the while loop the $subtraction_total variable would be $subtraction_total1+$subtraction1, because at the bottom of the page I would like to show the $total minus the $subtraction_total1.
But the first time in the while loop I must check if $subtraction_total already exists. I know to options to do that, but is there a shorter way?
Option 1 is to define the variable $subtraction_total1 before the while loop.
Option 2 is to do this:
(!isset($total_subtraction1)){$total_subtraction1=0;}$total_subtraction1=$total1-$subtraction1;
Now you think: well, just do option 1: define 1 variable, but it is for around 15 variables and I was just wondering if there is a shorter way;-)
Hope you understand me, my English is not very good;-)
Define and initialize all your variables before use. I think Option 1 follows logically from that.
Don't try to write code that is short, or fast or tricky. Write code that is easy to read and maintain.
I would definitely advocate defining the variable(s) before the loop. Repeatedly calling isset (or any other function) over and over inside a loop is wasteful if the same functionality can be achieved pre-loop.
If you're simply looking to define a large number of variables without having to explicitly declare each one before your loop you might try listdocs or programmatically create your variables in a loop.
$sub_total = 0;
while ($sub = mysql_get_row(...)) {
$sub_total += $sub;
}
This way you don't execute the same code again in every iteration (which is good practice and good performance wise), and it has the added advantage that if you have no result from mysql, $sub_total is defined with a default value.
Related
I always declare my array... good practice, I guess. Like so:
$image_rows = [];
But, am I being to picky by also declaring an array that exists inside a foreach loop. If I do declare it, are there any negatives?
$image_rows = [];
$vrow = [];
foreach($image_rows as $vrow) {
...
}
This would only make sense if you need $vrow after the loop to hold the last iteration’s value, and there’s a chance $image_rows may be empty, and you’re thus establishing a default value.
It has absolutely no use whatsoever if $vrow is supposed to be used inside the loop only. The potential harm here would be that by declaring it outside the loop, you’re implying a different use case to future readers of this code. Also, should you accidentally (or as a consequence of confusing yourself with your own implications) refer to $vrow after the loop, your IDE and/or PHP won’t give you a warning and just let you continue working with what’s probably the wrong value.
I'm writing some code that builds up associative array of counters. When it encounters a new item for the first time it creates a new key and initializes it to zero. I.e.:
if (!array_key_exists($item, $counters)) {
$counters[$item] = 0;
}
$counters[$item]++;
However, PHP actually does that first part implicitly. If I just do...
$counters[$item]++;
... then $counters[$item] will evaluate to NULL and be converted to 0 before it's incremented. Obviously the second way is simpler and more concise, but it feels a little sleazy because it's not obvious that $counters[$item] might not exist yet. Is one way or the other preferred in PHP?
For comparison, in Python the idiomatic approach would be to use collections.Counter when you want keys that initialize themselves to 0, and a regular dictionary when you want to initialize them yourself. In PHP you only have the first option.
Incrementing an uninitialized key will generate a PHP Notice, and is a bad idea. You should always initialize first.
However, the use of array_key_exists is not very idiomatic. I know coming from Python it may seem natural, but if you know that $counter has no meaningful NULL values it's more idiomatic to use isset() to test for array membership. (It's also much faster for no reason I can discern!)
This is how I would write a counter in PHP:
$counters = array();
foreach ($thingtobecounted as $item) {
if (isset($counters[$item])) {
$counters[$item]++;
} else {
$counters[$item] = 1;
}
}
Unfortunately unlike Python PHP does not provide any way to do this without performing two key lookups.
the first is preferred. the second option will generate a Notice in your logs that $counters[$item] is undefined. it still works but if you change display_errors = On; and error_reporting = E_ALL. in your php.ini file you will see these notices in your browser.
The first way is generally how you do it, if for nothing other than simpler maintenance. Remember, you may not be the one maintaining the code. You don't want error logs riddled with correctly operating code. Even worse, you may need to transfer methods to other languages (or earlier versions of PHP) where implicit initialization might not occur.
If you don't really need a check on each array index - or know that most of the indexes will be undefinded - why not suppress errors like: ?
(this way you save some performance on initializing [useless] indexes)
if (#!array_key_exists($item, $counters)) {
As far as I know second and third expressions are executed every time in a for loop.
I always took for granted performance wise second option is recommended, can anyone confirm this?
1) for($i=0;$i<=dosomething();$i++) [...]
2)
$max = dosomething();
for($i=0;$i<=$max;$i++) [...]
You shouldn't call a function inside of a loop definition because that function will be executed every iteration. When you only have a small loop the effect is negligible, however if you have a loop of hundreds or thousands of iterations you'll definitely notice.
But even if you only have a small loop, it's just bad practice. So in a word: don't.
Unless your dosomething() function returns different values and it can be done in a single shot, it's better to use the second method.
$options = array(1,2,3,4,5);
$element_count = count($options);
Functions like count() that returns same value in multiple calls can be saved in a one variable and use it in your for loop.
If you are very strict for performance, use ++$i instead of $i++
The second method is always going to preform better, especially if there is substantial work to be done in doSomething(). If you are only doing tens of loops, and doSomething() is just returning a local variable, then it won't make a noticeable difference.
Yes I confirm you can search benchmarks if you want.
Though I don't know if it's true if it's only a getter to an object
Is it possible to flush all variables in running page or can I get the all variable list which are already stored some data?
Have a look at
get_defined_vars()
http://php.net/manual/en/function.get-defined-vars.php
If you want to print the full list of variables (including superglobals) just:
print_r(array_keys(get_defined_vars()));
Also, as some others have mentioned in comments, if you need this you way want to think about reducing the number of variables you're using. The three easiest ways to do this (in my experience) are to overwrite variables when appropriate, for instance (silly example):
$subtotal = 0;
for($i=0;$i<10;$i++){
$subtotal = $subtotal + $i;
}
$total = $subtotal;
can be better written:
for($total=0;$total <10;$total++){
//nothing, I'm just itterating
}
which allows you to have one a single variable rather than three (this will also reduce memory allocation). The other useful trick is to store related variables in array or objects. For instance, instead of:
$number_of_widgets = 10;
$size_of_widgets = '120cm';
$cost_of_widgets = '$10.00';
$number_of_cogs = 13;
$size_of_cogs = '40cm';
$cost_of_cogs = '$3.00';
it is much easier to keep track of (and help prevent accidental variable-overwriting) if you add them to associative arrays:
$widgets = array('quantity'=>10,'size'=>'120cm','cost'=>'$10.00');
$cogs = array('quantity'=>13,'size'=>'400cm','cost'=>'$3.00');
And finally, if your variable isn't going to be modified (and isn't an array) just use a defined constant:
define('MAX_WIDGET_QUANTITY',300);
This has the advantage that (a) it's really easy to manage in the future if you ever want to change these contraints, (b) it's automatically available at the global scope, and (c) it makes code easier to read, as it is apparent that it is supposed to be a fixed value and should not be modified.
There are other tricks as well, but these will usually get you a long way towards variable manageability.
You can use get_defined_vars to do this.
From the linked page:
This function returns a multidimensional array containing a list of
all defined variables, be them environment, server or user-defined
variables, within the scope that get_defined_vars() is called.
So this would give you the names of all the variables:
array_keys(get_defined_vars())
In some code I'm working on I have noticed that several variables are being accessed from outside of foreach loops.
This is seen in codeigniter view files of this particular app.
For example, a view file:
<?php
foreach ($items as $row):
endforeach;
// HTML / PHP code...
<td>
<?php echo form_checkbox('option_1','1', FALSE); ?>
<?php echo form_hidden('weight_unit', $row->weight_unit); ?>
</td>
// etc...
This works (ie, no errors) but I wonder if this would be considered a bad practice and if so, why? (scope, etc)
Does anyone have an opinion on this and should variables only be called inside their corresponding loops?
Another issue I've noticed is if a variable is required in several parts of a view file: should I refactor to have multiple loops or should there be a single foreach / endforeach and the begin / end of the file.
Any suggestions are much appreciated. Thanks.
The only reason I could think of doing that is to seek to the end of the array so you can store its last member in a variable.
You can do this clearer with end().
$row = end($items);
$row will be the last item in the array, or unset, when it reaches your other code.
Is that want you want? If so, then it's not bad practice, per se. But you should at least document that the behavior is intended, because it's not intuitive.
Better practice is something like:
foreach ($foo as $bar)
{
// do something
}
$last_bar = isset($bar) ? $bar : null;
There it's obvious that you mean to do something with $last_bar.
Another issue I've noticed is if a variable is required in several parts of a view file
If you must iterate over your loop in different places in your view, then that's okay.
But if you just need a certain piece of information deep inside some array, then you should stick it into an easily accessible variable and use that instead.
This is a bad practice. If the recordset is more than one item long then you are looping through all the records (even though you do nothing in the loop) and then just using the last record. I dont use CI but if this is a recordset object there ought to be someway to access the first/last record or any other index position in the RS. You should use those if youre after a particular record. If its just an array you could use array_pop if you dont need to keep the array intact, or end if you do.
Additionally, in the same context of a lengthy set if its not really the last record your after this could have unforseen consequences if the recordset length changes.
I'd say this is really bad practice - what happens if later (in a few weeks) you come across the same piece of code and you need another foreach on totally different record types between the actual foreach and your table? - your $row variable will then have a totally different meaning - this piece of code is very susceptible to side effects when more code is added.
Also, there is a high possibility that in the future this behavior will not be supported by PHP anymore (this is just an assumption of mine, because, as you mentioned, the $row variable is out of scope where you are using it).
As some general principles:
use as few as possible global variables - they are hard to track, maintain and assure correct values
minimize the scope of the variables as much as possible and use them only in very clear scopes
avoid marginal use cases and so called features that are totally unnatural in other languages
last, but not least, avoid the principle if code was hard to write it should be hard to read - this principle won't secure you the job, only the hate of your coworkers