Suppose I have an array of nodes (objects). I need to create a duplicate of this array that I can modify without affecting the source array. But changing the nodes will affect the source nodes. Basically maintaining pointers to the objects instead of duplicating their values.
// node(x, y)
$array[0] = new node(15, 10);
$array[1] = new node(30, -10);
$array[2] = new node(-2, 49);
// Some sort of copy system
$array2 = $array;
// Just to show modification to the array doesn't affect the source array
array_pop($array2);
if (count($array) == count($array2))
echo "Fail";
// Changing the node value should affect the source array
$array2[0]->x = 30;
if ($array2[0]->x == $array[0]->x)
echo "Goal";
What would be the best way to do this?
If you use PHP 5:
Have you run your code? It is already working, no need to change anything. I get:
Goal
when I run it.
Most likely this is because the values of $array are already references.
Read also this question. Although he OP wanted to achieve the opposite, it could be helpful to understand how array copying works in PHP.
Update:
This behaviour, when copying arrays with objects, the reference to the object is copied instead the object itself, was reported as a bug. But no new information on this yet.
If you use PHP 4:
(Why do you still use it?)
You have to do something like:
$array2 = array();
for($i = 0; $i<count($array); $i++) {
$array2[$i] = &$array[$i];
}
it is some time that I don' write PHP code, but does the code
// Some sort of copy system
$array2 = $array;
actually work?
Don't you have to copy each element of the array in a new one?
Related
Hey in a recent project I got this working and was quite amazed that such a snipped works.
$parentRef = &$elements[$targetPath]->
{$contentTypeMap[$contentTypeIdMap[$contentTypeId]]};
if(is_array($parentRef)) {
$parentRef = &$parentRef[];
}
$parentRef = $element;
It was quite intuitive that it might work that way but what exactly is
$parentRef[] returning to make this work?
If I var_dump it, i get null.
Here is a simplified example which seems to work.
<?php
$arr = [1, 2];
$ref = &$arr[];
$ref = 3;
foreach($arr as $n) {
echo $n;
}
This example returns 123 just to verify that it works.
In your example $arr[] will create new element in array with NULL value. The ampersand is reference to this position, so when you store something to $ref, it will be stored in this new position, because $ref is just reference (something like pointer, but its not pointer!) to this new element in array
how to slice an array to pass it to a function. I cannot use unset because I need that array further. I know I can copy whole array to variable, however it's quite big and don't thing it's efficient. My code:
$list = array(0=>2123, 2=>1231, 7=>123123,...);
unset($list[0]); //I can't do this because I still need whole $list
$seats = $allocatingClass->allocateSeats($seatsNumber, $list); //here I need to slice $key from $list and pass $list without reiterating
If you need to keep index 0, store it, rather than storing the entire array elsewhere:
$tmp = $list[0];
Then splice the array:
$list = array_splice($list,1,count($list));
Then pass it to your function:
$seats = $allocatingClass->allocateSeats($seatsNumber, $list);
Then, when you need it, put back the value to the array:
$list[] = $tmp;
Edit: if you actually need to put it exactly at index 0, then you may want to unset the index 0 of the array instead of splicing it. If you can, however, push it at the end of the array just follow what is written above.
To clearify, if you need to LATER push back the element to index 0, do
unset($list[0]);
instead of the splice...
And to put back the element, do:
$list[0] = $tmp;
However you do it, a copy will be made when passing the array (unless you pass it by reference).
either use splice. or create a copy and shift one value.
after sending the copy variable, you can unset it so it wont keeptaking its space.
Edit :
The above solution is also viable. Though I suggest you use:
$tmp = array_shift($arr);
doStuf($arr);
array_unshift($arr, $tmp);
I have an array containing several keys, values, objects etc.. I need to empty that array but I'd like to do it in the most efficient manner.
The best I can come up with is:
foreach ($array as $key => $val) unset($array[$key]);
But I don't like the idea of having to loop through the array to just empty it.. surely there's a nice slick/clever way of doing this without wasting memory creating a new array?
Note: I'm not sure myself if it does cost extra memory in creating the array as new again. If it doesn't then $array = new array(); would be a fine way of 'emptying' it.
Just try with:
$array = array();
It highly depends on what you mean.
To empty the current reference you can always do
$array = array();
To completely remove the current instance from the scope
unset($array);
Unfortunately both of these cases don't necessarily mean the memory associated with each element is released.
PHP works with something called "references" for your variables. Your variables are actually labels or references pointing to data, not the actual container for data.
The PHP garbage collector can offer more insight on this subject.
Now take a look at this example, taken from the docs:
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );# a: (refcount=3, is_ref=0)='new string'
unset( $b, $c );
xdebug_debug_zval( 'a' );# a: (refcount=1, is_ref=0)='new string'
This unfortunately applies to all your variables. Including arrays. Cleaning up the memory associated with the array is a whole different subject I'm afraid.
I've noticed a longer discussion in the comments regarding using unset() on each individual key.
This feels like extremely bad practice. Consider the following code:
class A{
function __construct($name){$this->name=$name;}
function __destruct(){echo $this->name;}
}
$a=array();
$b=array();
$c=array();
for($i=0;$i<5;$i++) {
$a[]=new A('a');
$b[]=new A('b');
$c[]=new A('c');
}
unset($a);
$b=array();
echo PHP_EOL.'done'.PHP_EOL;
This will output:
aaaaabbbbb
done
ccccc
When the reference to a particular data structure reaches 0, it is cleaned from memory.
Both =array() and unset will do the same thing.
Now if you don't actually need array() you can use null :
$array=null;
This keeps the label in memory, but removes the reference it held to any particular data.
It's simple:
$array = array();
$array will be existing and type of array (but empty), and your data can be garbaged later from memory.
Well... why not: $array = array(); ?
As Suresh Kamrushi pointed out, I could use array_keys:
foreach (array_keys($array) as $key) unset($array[$key]);
This is probably the nicest solution for now.. but I'm sure someone will come up with something better soon :)
Try this:
// $array is your original array
$array = array_combine( array_keys( $array ), array_fill( 0, count($array), 0 ) );
The above will blank your array keeping the keys intact.
Hope this helps.
In the PHP manual, (array_push) says..
If you use array_push() to add one element to the array it's better to
use $array[] = because in that way there is no overhead of calling a
function.
For example :
$arr = array();
array_push($arr, "stackoverflow");
print_r($arr);
vs
$arr[] = "stackoverflow";
print_r($arr);
I don't understand why there is a big difference.
When you call a function in PHP (such as array_push()), there are overheads to the call, as PHP has to look up the function reference, find its position in memory and execute whatever code it defines.
Using $arr[] = 'some value'; does not require a function call, and implements the addition straight into the data structure. Thus, when adding a lot of data it is a lot quicker and resource-efficient to use $arr[].
You can add more than 1 element in one shot to array using array_push,
e.g. array_push($array_name, $element1, $element2,...)
Where $element1, $element2,... are elements to be added to array.
But if you want to add only one element at one time, then other method (i.e. using $array_name[]) should be preferred.
The difference is in the line below to "because in that way there is no overhead of calling a function."
array_push() will raise a warning if the first argument is not
an array. This differs from the $var[] behaviour where a new array is
created.
You should always use $array[] if possible because as the box states there is no overhead for the function call. Thus it is a bit faster than the function call.
array_push — Push one or more elements onto the end of array
Take note of the words "one or more elements onto the end"
to do that using $arr[] you would have to get the max size of the array
explain:
1.the first one declare the variable in array.
2.the second array_push method is used to push the string in the array variable.
3.finally it will print the result.
4.the second method is directly store the string in the array.
5.the data is printed in the array values in using print_r method.
this two are same
both are the same, but array_push makes a loop in it's parameter which is an array and perform $array[]=$element
Thought I'd add to the discussion since I believe there exists a crucial difference between the two when working with indexed arrays that people should be aware of.
Say you are dynamically creating a multi-dimensional associative array by looping through some data sets.
$foo = []
foreach ($fooData as $fooKey => $fooValue) {
foreach ($fooValue ?? [] as $barKey => $barValue) {
// Approach 1: results in Error 500
array_push($foo[$fooKey], $barKey); // Error 500: Argument #1 ($array) must be of type array
// NOTE: ($foo[$fooKey] ?? []) argument won't work since only variables can be passed by reference
// Approach 2: fix problem by instantiating array beforehand if it didn't exist
$foo[$fooKey] ??= [];
array_push($foo[$fooKey], $barKey);
// Approach 3: One liner approach
$foo[$fooKey][] = $barKey; // Instantiates array if it doesn't exist
}
}
Without having $foo[$fooKey] instantiated as an array beforehand, we won't be able to do array_push without getting the Error 500. The shorthand $foo[$fooKey][] does the heavy work for us, checking if the provided element is an array, and if it isn't, it creates it and pushes the item in for us.
I know this is an old answer but it might be helpful for others to know that another difference between the two is that if you have to add more than 2/3 values per loop to an array it's faster to use:
for($i = 0; $i < 10; $i++){
array_push($arr, $i, $i*2, $i*3, $i*4, ...)
}
instead of:
for($i = 0; $i < 10; $i++){
$arr[] = $i;
$arr[] = $i*2;
$arr[] = $i*3;
$arr[] = $i*4;
...
}
edit- Forgot to close the bracket for the for conditional
No one said, but array_push only pushes a element to the END OF THE ARRAY, where $array[index] can insert a value at any given index. Big difference.
I'm using a nestedsortable jQuery plugin that gives me the order/sort of the elements serialized.
And example of this serialitzation (root means parent_id=0):
id[1]=root&id[5]=1&id[2]=1&id[3]=1&id[4]=3
First thing I'll do is explode by &:
$serialized = "id[1]=root&id[5]=1&id[2]=1&id[3]=1&id[4]=3";
$exploded = explode("&", $serialized);
But I don't know then how to manage a id[1]=root or id[3]=1. How I can do it?
And another question. In this way I don't know which is how to store the order. When I've the exploded with in array like array("id"=>1, "parent"=>"root"); I've to store the order. I will do it with an index, but how I recognise nested levels?
An example:
$i = 0;
foreach($exploded as $explode)
{
//update every id in MySQL and set parent=$explode["parent"] and order=$i
$i++;
}
But if I've N levels, how I can have a index $i for every one of them?
Thank you in advance!
Rather than exploding, you could try parse_str()
<?php
parse_str("id[1]=root&id[5]=1&id[2]=1&id[3]=1&id[4]=3",$result);
print_r($result);
?>
From there you can work with the array.