Will this foreach copy the values in memory? - php

Example:
foreach ($veryFatArray as $key => $value) {
Will the foreach assign the value behind the $key by reference to $value, or will $value be a copy of what's stored in the array? And if yes, how could I get an reference only? The array values store pretty big amounts of data so copying them is not really good.

Don't try and second-guess the interpreter is the moral of the story here. $value is actually a copy but an efficient copy. PHP uses pass-by-value (for non-objects) but also uses copy-on-write. What this means is that if you write:
foreach ($bigitems as $bigitem) {
echo $bigitem; // uses original
$bigitem = 'foo'; // item copied and assigned 'foo'
echo $bigitem; // uses copy
}
Just declare your intent: that you want to use the array values. Let PHP sort it out after that. Basically only use references in the loop like this if you intend to change the array. Otherwise you're sending the wrong message to someone else who reads your code.
Section 1 of Copy-on-Write in the PHP Language should tell you everything you ever wanted to know about PHP copy-on-write.

$value will be a copy, but (please someone correct me if I'm wrong here), PHP is actually very smart about pass-by-value type things. It will actually do a pass-by-reference and only copy if you modify the variable. For example:
function foo ($bar) {
echo $bar['x'];
// internally, $bar is a reference to $baz. (virtually) no extra memory used
$bar['y'] = 'Y';
// only now has the array been copied in memory
}
$baz = array('x' => '1', 'y' => '2');
foo($baz);
In your foreach, if you want to modify the original array, you could do this:
// PHP 4
foreach (array_keys($veryFatArray) as $key) {
$value =& $veryFatArray[$key];
// ...
}
// PHP 5
foreach ($veryFatArray as $key => &$value) { }
If you are only reading from $value and not writing to it, then it shouldn't be a problem.

Related

PHP Object References?

I've read up about PHP variable references but I'm not 100% and was hoping someone could help.
If I have a class like the following:
class Item
{
public $value;
}
I then have an array of those items in a variable - lets call that $items. All I did was new Item()...and $items[] = $newItem;.
Now, I want to populate another array but it filters the original array based on its value. So like the following:
foreach($items as $key => $value)
{
$filteredItems[] = &value;
}
Now, I have ANOTHER variable that iterates over that filtered list and does something like so:
$theItem = $filteredItems[10];
$theItem->value = 100;
Now this is where I'm confused. Do I need to set $theItem to &filteredItems[10]; (reference) or will it just know that the value in the array is a reference type and $theItem also becomes a reference to that same item? I'm after that last set of $theItem->value = 100; changes the very original object stored in the $items list.
In PHP 5 objects are always passed around by their "handle" for lack of better word. This means if you do this:
$a = new Item();
$a->value = 1;
$b = $a;
$b->value++;
echo $a->value;
The value of 2 is echoed. Why? Because the handle of the object is copied from $a to $b and they both point to the same object. This isn't a reference in terms of using &, but behaves similarly enough to the point that people generally call it the same thing... even though it's not.
So you do not need any use of references in your code. Usually in PHP, you never need to use references when using objects.
With respect to objects, you really only notice references if you do this (assign a new value to the variable itself):
function foo(Item &$a)
{
$a = null;
}
$b = new Item();
foo($b);
var_dump($b);
This results in NULL, which wouldn't happen without a reference. But again, this is not typical usage, so you can really forget about using references with objects.
(And of course the use of a function isn't necessary here to illustrate the point, but that's the most typical place you'll see them in the "real world.")
It's like this:
foreach($items as $key => &$value) {
$filteredItems[] = $value;
}
The point where you give the original instance into a different scope is where you put the &.
Same is for functions:
function myFunction(&$variable) { }
Example:
<?php
class test {
public $testVar;
public function __construct() {
$this->testVar = "1";
}
}
function changeByReference(&$obj) {
$obj->testVar = "2";
}
$instance = new test();
// Prints 1
echo $instance->testVar, PHP_EOL;
changeByReference($instance);
// Prints 2
echo $instance->testVar, PHP_EOL;
Read more about it here: http://php.net/manual/en/language.oop5.references.php
If you want to copy an instance, use clone - php.net/clone
The easiest way to get it is when you know the difference between these: class, object and instance. (I'd explain it more at this point but it would only confuse you more because my english is not accurate enough for now to explain the details enough.)

PHP variable variable name containing index

$arr[0]=123;
$a="arr[0]";
echo $$a;
gives me error
Notice: Undefined variable: arr[0]
on the last line.
What should I do to make it work?
EDIT:
Above is the simplification of what I want to do. If someone wants to know why I want to do this, then here's the explanation:
This is something like what I want to do:
if(condition){
$a=$arr1[0][0];
$b=$arr1[0][1];
$c=$arr1[0][2];
}
else{
$a=$arr2[0];
$b=$arr2[1];
$c=$arr2[2];
}
I can compact it like this:
if(condition)
$arr=$arr1[0];
else
$arr=$arr2;
$a=$arr[0];
$a=$arr[1];
$a=$arr[2];
But I wanted to try doing this using variable variable:
if(condition)
$arr="$arr1[0]";
else
$arr="$arr2";
$a={$$arr}[0];
$b={$$arr}[1];
$c={$$arr}[2];
Sure, we don't need variable variables as we can still code without them. I want to know, for learning PHP, why the code won't work.
Now that you said what you’re actually trying to accomplish: Your code doesn’t work because if you look at $arr1[0][0], only arr is the variable name; the [0] are special accessors for certain types like strings or arrays.
With variable variables you can only specify the name but not any accessor or other operation:
A variable variable takes the value of a variable and treats that as the name of a variable.
Your solution with the additional variable holding the array to access later on would be the best solution to your problem.
What you are trying to do just won't work - the code $arr[0] is referencing a variable called $arr, and then applying the array-access operator ([$key]) to get the element with key 0. There is no variable called $arr[0], so you cannot reference it with variable-variables any more than you could the expression $foo + 1 .
The real question is why you want to do this; variable variables are generally a sign of very messy code, and probably some poor choices of data structure. For instance, if you need to select one of a set of variables based on some input, you probably want a hash, and to look up an item using $hash[$item] or similar. If you need something more complex, a switch statement can often cover the cases you actually need.
If for some reason you really need to allow an arbitrary expression like $arr[0] as input and evaluate it at runtime, you could use eval(), but be very very careful of where the input is coming from, as this can be a very easy way of introducing security holes into your code.
FROM PHP DOC
In order to use variable variables with arrays, you have to resolve an ambiguity problem. That is, if you write $$a[1] then the parser needs to know if you meant to use $a[1] as a variable, or if you wanted $$a as the variable and then the [1] index from that variable. The syntax for resolving this ambiguity is: ${$a[1]} for the first case and ${$a}[1] for the second.
Use
echo ${$a}[0]; // 123
Edit : Based on your edit you can simply have
list($a, $b, $c) = (condition) ? $arr1[0] : $arr2;
Or
$array = (condition) ? $arr1[0] : $arr2;
$a = $array[0];
$b = $array[1];
$c = $array[2];
As pointed out you don't need variable variables. To get a PHP variable variable name containing index (a key) use array_keys() or array_search() or other array parsers. From php's site:
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
You could also use the following (using $var= instead of echo):
$arr[0]=123;
$arr[1]=456;
foreach ($arr as $key => $value) {
echo "arr[{$key}] = {$value} \r\n";
}
Which outputs:
arr[0] = 123
arr[1] = 456
But I don't see why you'd do that, since the whole point of the array is not doing that kind of stuff.

Reusing collection var as iteration var in a PHP foreach

I have a coworker that I noticed was using his foreachs in the following fashion:
foreach ($var as $var) {
// do stuff here
}
I have tested the code above and it works correctly to my surprise. Would the PHP gurus like to hop in and tell me why this is wrong? It feels very wrong.
Because it changes the value of $var. After the foreach() it's no longer an array but is set to the last value in the array.
$var = array('apple', 'orange');
foreach ($var as $var) {
echo $var."<br/>";
}
echo $var; //orange
If you don't want to change the variable's value, it'll need to be a different variable name:
$var = array('apple', 'orange');
foreach ($var as $fruit) {
echo $fruit."<br/>";
}
echo $var; //array
As #UselessIntern pointed out, it's fine if you're not going to use the variable after looping through it, but it's definitely not encouraged because it can lead to confusion.
As #PLB pointed out, it iterates over a copy of the $var not $var itself. So every iteration the value of $var is changing, but it doesn't break the loop because it's looping over the copy that was created.
Because it's a loop. Performing:
array > string
array > string
So
foreach ($var AS $var){
/*
Is basically being re-read at the end so your foreach can read the array again to get the next step of the array
array > string
recheck array > string
recheckarray > string
*/
}
Even it feels wrong, it still works because the moment the foreach starts, PHP internally has already access on the data.
So even $var gets overwritten, in memory this data is still present (the original array) and $var is set in each iteration to the current value of it.
The concrete problem you've spotted and about which you say is wrong is also known as variable-reuse which you should prevent because this is a code-smell.
It not only feels wrong, it is wrong to write such code. Tell your co-worker so you can write better code together.
Your coworker seems to don't need $var as an array after the loop anymore. When PHP initializes the foreach loop (what is done only once) it uses the original values from $var as it is an array at the moment. Then on every step in the loop the current element of the element is assigned to a new var called var. Note that the orginal array $var doesn't exist anymore. After the loop $var will have the value of the last element in the original array.
check this little example which demonstrates what I've said:
$a = array(1,2,3);
foreach($a as $a) {
echo var_dump($a);
}
// after loop
var_dump($a); // integer(3) not array
I could imaging that your coworker does this to save a little memory as the reference to the array will get overwritten and therefore the garbage collector will remove it's memory on next run, but I would not advice you to do the same, as it's less readable.
Just do the following, which is the same but is much more readable:
$array = array(1,2,3);
foreach($array as $value) {
echo var_dump($value);
}
delete($array);
delete($value);
Check this expression:
$x = array(1,2,3);
foreach ($x as $x) {
echo $x; //prints 123
}
What is happening here is that the foreach extracts the first element of array $x and overrides into $x itself. However the array variable $x which was on the left side of the as keyword remains in internal scope of the foreach argument which is why the looping works without problems.
Once the loop completes the $x which was internal to the foreach (the array) loses scope and no longer exists, and what remains is the $x variable which now contains the last element of the original $x array. In this case that would be 3.

define multiple results all at the same time in php

I have $config variable that have arrays inside it. In smarty I assign the variable like this:
$smarty->assign('config', $config);
when I call it, I used this : {$config.wateverarrayyouwant}
now I want to do the same thing with php. I want to define them in the same manner. How can I define all the arrays in $config in just one line?
I only know how to define a variable one at a time by using this :
define('wateverarrayyouwant', $config['wateverarrayyouwant']);
I tried changing wateverarrayyouwant to a variable because it can be any array :
define('$wateverarrayyouwant', $config[$wateverarrayyouwant]);
but the code above does not work. what is a good way to achieve what I want?
If you want to create a define for each key value pair in the array you can use:
<?php
foreach($config as $key => $value) {
define($key, $value);
}
I will note however that you cannot define array values, all define's must be scalar:
The value of the constant; only scalar and null values are allowed. Scalar values are integer, float, string or boolean values.
If you check the OP's answer for further explanation of what he's trying to achieve, it can be done with:
<?php
foreach($config as $key => $value){
$$key = $value;
}
?>
This question cannot be done. because I am trying to define a variable as a constant. I was just thinking about how can I reduce the letters for variables and never though that I better leave them alone. Logically, why do somebody need to change $config[$wateverarrayyouwant] to wateverarrayyouwant. I was only thinking about maintaining a neat code. but now I am thinking about it.. it is better to leave it as it is : $config[$wateverarrayyouwant]
This can be done with:
foreach($config as $key => $value){
$$key = $value;
}
You may not even want to use define here. define is used to create constants not plain variables and that carries with it certain connotations:
they are immutable for the life of the script
they must be scalar
If you just want an array variable then define it like normal with:
$whatever = array(
'key1' => 'value1'
);

Efficiency of using foreach loops to clear a PHP array's values

Which is more efficient for clearing all values in an array? The first one would require me to use that function each time in the loop of the second example.
foreach ($array as $i => $value) {
unset($array[$i]);
}
Or this
foreach($blah_blah as $blah) {
$foo = array();
//do something
$foo = null;
}
I don't want to use unset() because that deletes the variable.
Like Zack said in the comments below you are able to simply re-instantiate it using
$foo = array(); // $foo is still here
If you want something more powerful use unset since it also will clear $foo from the symbol table, if you need the array later on just instantiate it again.
unset($foo); // $foo is gone
$foo = array(); // $foo is here again
If we are talking about very large tables I'd probably recommend
$foo = null;
unset($foo);
since that also would clear the memory a bit better. That behavior (GC) is however not very constant and may change over PHP versions. Bear in mind that re-instantiating a structure is not the same as emptying it.
If you just want to reset a variable to an empty array, you can simply reinitialize it:
$foo = array();
Note that this will maintain any references to it:
$foo = array(1,2,3);
$bar = &$foo;
// ...
$foo = array(); // clear array
var_dump($bar); // array(0) { } -- bar was cleared too!
If you want to break any references to it, unset it first:
$foo = array(1,2,3);
$bar = &$foo;
// ...
unset($foo); // break references
$foo = array(); // re-initialize to empty array
var_dump($bar); // array(3) { 1, 2, 3 } -- $bar is unchanged
Unsetting the variable is a nice way, unless you need the reference of the original array!
To make clear what I mean:
If you have a function wich uses the reference of the array, for example a sorting function like
function special_sort_my_array(&$array)
{
$temporary_list = create_assoziative_special_list_out_of_array($array);
sort_my_list($temporary_list);
unset($array);
foreach($temporary_list as $k => $v)
{
$array[$k] = $v;
}
}
it is not working! Be careful here, unset deletes the reference, so the variable $array is created again and filled correctly, but the values are not accessable from outside the function.
So if you have references, you need to use $array = array() instead of unset, even if it is less clean and understandable.
I'd say the first, if the array is associative. If not, use a for loop:
for ($i = 0; $i < count($array); $i++) { unset($array[$i]); }
Although if possible, using
$array = array();
To reset the array to an empty array is preferable.
Isn't unset() good enough?
unset($array);
How about $array_name = array(); ?
Use array_splice to empty an array and retain the reference:
array_splice($myArray, 0);
i have used unset() to clear the array but i have come to realize that unset() will render the array null hence the need to re-declare the array like for example
<?php
$arr = array();
array_push($arr , "foo");
unset($arr); // this will set the array to null hence you need the line below or redeclaring it.
$arr = array();
// do what ever you want here
?>
Maybe simple, economic way (less signs to use)...
$array = [];
We can read in php manual :
As of PHP 5.4 you can also use the short array syntax, which replaces array() with [].
I see this questions is realla old, but for that problem I wrote a recursive function to unset all values in an array. Recursive because its possible that values from the given array are also an array. So that works for me:
function empty_array(& $complete_array) {
foreach($complete_array as $ckey => $cvalue)
{
if (!is_array($cvalue)) {
$complete_array[$ckey] = "";
} else {
empty_array( $complete_array[$ckey]);
}
}
return $complete_array;
}
So with that i get the array with all keys and sub-arrays, but empty values.
The unset function is useful when the garbage collector is doing its rounds while not having a lunch break;
however unset function simply destroys the variable reference to the data, the data still exists in memory and PHP sees the memory as in use despite no longer having a pointer to it.
Solution:
Assign null to your variables to clear the data, at least until the garbage collector gets a hold of it.
$var = null;
and then unset it in similar way!
unset($var);
The question is not really answered by the posts. Keeping the keys and clearing the values is the focus of the question.
foreach($resultMasterCleaned['header'] as $ekey => $eval) {
$resultMasterCleaned[$key][$eval] = "";
}
As in the case of a two dimensional array holding CSV values and to blank out a particular row. Looping through seems the only way.
[] is nearly 30% faster then as array()
similar as pushing new element to array
$array[] = $newElement then array_push($array, $newElement)
(keep in mind array_push is slower only for single or 2 new elements)
Reason is we skip overhead function to call those
PHP array vs [ ] in method and variable declaration

Categories