Bug or hack? $GLOBALS - php

$GLOBALS["items"] = array('one', 'two', 'three', 'four', 'five' ,'six', 'seven');
$alter = &$GLOBALS["items"]; // Comment this line
foreach($GLOBALS["items"] as $item) {
echo get_item_id();
}
function get_item_id(){
var_dump(key($GLOBALS["items"]));
}
Check output of this code, with commented and uncommented second line.
My result(PHP 5.3.0).
With second line
int(1) int(2) int(3) int(4) int(5) int(6) NULL
Without second line:
int(1) int(1) int(1) int(1) int(1) int(1) int(1)
Why so strange result?

Here is a possible explanation:
We know that foreach always loops over a copy of the array if it is not referenced:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer.
That means that the internal pointer of the original array is not changed and key() will always return the same value (as we can see when we comment out the line). And indeed if we do a var_dump($GLOBALS), we get:
["items"]=>
array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
(no reference)
But as soon as we generate a reference to the array (with $alter), $GLOBALS['items'] becomes a reference too, because both entries have to point to the same array:
["items"]=>
&array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
["alter"]=>
&array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
Hence, the foreach loop does iterate over the original array and changes the internal pointer, which affects key().
To sum up: It is a problem with references, not with $GLOBALS.

Related

How to rotate element of an array in top to bottom fashion in every iteration

I have an array of n size
suppose my original array is:
array=(alpha,bravo,charlie,delta,echo,foxtrot);
and i want to rotate the above array in leftward
ex output 1st iteration
array=(bravo,charlie,delta,echo,foxtrot,alpha);
and 2nd iteration
array=(charlie,delta,echo,foxtrot,alpha,bravo);
and i want to do this in every iteration till original array is achieved.
Note :The above array i am getting from MySQL output for a specific query. So the original array will be always array=(alpha,bravo,charlie,delta,echo,foxtrot);
Thanks in Advance for any suggestion and help
$array = array('alpha','bravo','charlie','delta','echo','foxtrot');
for($i=0; $i< count($array);$i++)
{
$firstValue = array_shift($array);
array_push($array, $firstValue);
var_dump($array); //here you get your array with the first value shifted to the end of the array
}
Result:
array(6) {
[0]=>
string(5) "bravo"
[1]=>
string(7) "charlie"
[2]=>
string(5) "delta"
[3]=>
string(4) "echo"
[4]=>
string(7) "foxtrot"
[5]=>
string(5) "alpha"
}
array(6) {
[0]=>
string(7) "charlie"
[1]=>
string(5) "delta"
[2]=>
string(4) "echo"
[3]=>
string(7) "foxtrot"
[4]=>
string(5) "alpha"
[5]=>
string(5) "bravo"
}
array(6) {
[0]=>
string(5) "delta"
[1]=>
string(4) "echo"
[2]=>
string(7) "foxtrot"
[3]=>
string(5) "alpha"
[4]=>
string(5) "bravo"
[5]=>
string(7) "charlie"
}
array(6) {
[0]=>
string(4) "echo"
[1]=>
string(7) "foxtrot"
[2]=>
string(5) "alpha"
[3]=>
string(5) "bravo"
[4]=>
string(7) "charlie"
[5]=>
string(5) "delta"
}
array(6) {
[0]=>
string(7) "foxtrot"
[1]=>
string(5) "alpha"
[2]=>
string(5) "bravo"
[3]=>
string(7) "charlie"
[4]=>
string(5) "delta"
[5]=>
string(4) "echo"
}
array(6) {
[0]=>
string(5) "alpha"
[1]=>
string(5) "bravo"
[2]=>
string(7) "charlie"
[3]=>
string(5) "delta"
[4]=>
string(4) "echo"
[5]=>
string(7) "foxtrot"
}

Merge array where duplicate in multidimensional array

I've been trying to merge this array ONLY WHERE $array[4] exists more than one time, example: $array[4] == 'red' exactly twice. How can I merge only those arrays while keeping the others? I have made several attempts at this and I am willing to include my efforts if asked.
Consider this array:
array(3) {
[0]=>
array(5) {
[0]=>
string(3) "UID"
[1]=>
string(3) "532"
[2]=>
string(1) "2"
[3]=>
string(9) "Domain(s)"
[4]=>
string(20) "red"
}
[1]=>
array(5) {
[0]=>
string(3) "UID"
[1]=>
string(3) "532"
[2]=>
string(7) "License"
[3]=>
string(3) "Fee"
[4]=>
string(20) "red"
}
[2]=>
array(5) {
[0]=>
string(3) "UID"
[1]=>
string(3) "536"
[2]=>
string(7) "License"
[3]=>
string(3) "Fee"
[4]=>
string(16) " University Test"
}
}
TRYING TO ACHIEVE:
array(3) {
[0]=>
array(5) {
[0]=>
string(3) "UID"
[1]=>
string(3) "532"
[2]=>
string(1) "2"
[3]=>
string(9) "Domain(s)"
[4]=>
string(20) " red"
[5]=>
string(3) "Fee"
[6]=>
string(7) "License"
}
[1]=>
array(5) {
[0]=>
string(3) "UID"
[1]=>
string(3) "536"
[2]=>
string(7) "License"
[3]=>
string(3) "Fee"
[4]=>
string(16) " University Test"
}
}
foreach ($test as $item) {
if (!isset($merged[$item[4]])) {
// add the item to the merged array using key=$item[4]
$merged[$item[4]] = $item;
} else {
// merge the item with the item that is already in the array at key=$item[4]
$merged[$item[4]] = array_unique(array_merge($merged[$item[4]], $item));
// array_unique is necessary because array_merge will not overwrite numeric keys
}
}
// convert the keys back to numeric (if you care to)
$merged = array_values($merged);

PHP_XLSwriter array output

I'm working with a bit of php code called PHP_XLSWriter. It accepts an input, then outputs it to an Excel sheet.
Their example.php page does exactly what I want, and in it, there's a bit of code that determines what specifically gets exported:
$data1 = array(
array('2003','1','-50.5','2010-01-01 23:00:00'),
array('2003','=B2', '23.5','2010-01-01 00:00:00'),
);
I haven't written arrays like this exactly in the past, but I've passed my own array into this page through AJAX from a separate page. I'm not sure if it's important how I did this, but I'm happy to paste in that code if it is.
When I try to execute the page using MY array, the page fails and my console is full of intelligible text.
I can't figure out why this is as the var_dump of our two arrays are exactly the same.
the original var_dump($data1);
array(2) {
[0]=>
array(4) {
[0]=>
string(4) "2003"
[1]=>
string(1) "1"
[2]=>
string(5) "-50.5"
[3]=>
string(19) "2010-01-01 23:00:00"
}
[1]=>
array(4) {
[0]=>
string(4) "2003"
[1]=>
string(3) "=B2"
[2]=>
string(4) "23.5"
[3]=>
string(19) "2010-01-01 00:00:00"
}
}
the var_dump() when I set $data1 equal to the array I've imported:
array(2) {
[0]=>
array(4) {
[0]=>
string(6) "blah"
[1]=>
string(12) "two"
[2]=>
string(6) "0.0160"
[3]=>
string(6) "0.0173"
}
[1]=>
array(4) {
[0]=>
string(3) "blah"
[1]=>
string(14) "three"
[2]=>
string(6) "0.0085"
[3]=>
string(6) "0.0095"
}
}
and echo gettype($data1); outputs array for both of the strings.
What might I be doing to cause this to break? I'm positive it has something to do with my array, as all else held equal, the code works.

browsing an array by reference is changing it (no actions done)

edit:do not read the related topic, the answer below is clear and gives the solution, while the other topic just states the issue.
I have something weird here
My code looks like this:
var_dump($resultFlatTree);
foreach($resultFlatTree as &$element)
{
/*if(isset($element["action"]) && $element["action"] == "new")
{
//let's save the original ID so we can find the children
$originalID = $element["id"];
//now we get the object
$newObject = $setUpForDimension->createAnObject($dimension,$element,$customer);
$element['id'] = $newObject->getId();
echo "new";
//and let's not forget to change the parent_id of its children
$arrayFunctions->arrayChangingValues($resultFlatTree,"parent_id",$element['id'],$originalID);
$em->persist($newObject);
} */
}
$em->flush();
var_dump($resultFlatTree);
the code inside the foreach is commented to be sure that it's not what I'm doing that's changing the array.
here the array before the foreach:
array(3) {
[0]=>
array(10) {
["id"]=>
int(2)
["name"]=>
string(7) "Revenue"
["code"]=>
string(6) "700000"
["sense"]=>
string(2) "CR"
["lft"]=>
int(1)
["lvl"]=>
int(2)
["rgt"]=>
int(1)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00D"
["parent_id"]=>
int(1)
}
[1]=>
array(10) {
["id"]=>
int(3)
["name"]=>
string(7) "Charges"
["code"]=>
string(6) "600000"
["sense"]=>
string(2) "DR"
["lft"]=>
int(3)
["lvl"]=>
int(2)
["rgt"]=>
int(4)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00P"
["parent_id"]=>
int(4)
}
[2]=>
array(10) {
["id"]=>
int(4)
["name"]=>
string(6) "Energy"
["code"]=>
string(6) "606000"
["sense"]=>
string(2) "DR"
["lft"]=>
int(2)
["lvl"]=>
int(1)
["rgt"]=>
int(5)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00E"
["parent_id"]=>
int(1)
}
}
and then after:
array(3) {
[0]=>
array(10) {
["id"]=>
int(2)
["name"]=>
string(7) "Revenue"
["code"]=>
string(6) "700000"
["sense"]=>
string(2) "CR"
["lft"]=>
int(1)
["lvl"]=>
int(2)
["rgt"]=>
int(1)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00D"
["parent_id"]=>
int(1)
}
[1]=>
array(10) {
["id"]=>
int(3)
["name"]=>
string(7) "Charges"
["code"]=>
string(6) "600000"
["sense"]=>
string(2) "DR"
["lft"]=>
int(3)
["lvl"]=>
int(2)
["rgt"]=>
int(4)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00P"
["parent_id"]=>
int(4)
}
[2]=>
&array(10) {
["id"]=>
int(4)
["name"]=>
string(6) "Energy"
["code"]=>
string(6) "606000"
["sense"]=>
string(2) "DR"
["lft"]=>
int(2)
["lvl"]=>
int(1)
["rgt"]=>
int(5)
["root"]=>
int(1)
["$$hashKey"]=>
string(3) "00E"
["parent_id"]=>
int(1)
}
}
As you can see, the last element is now changed and is by reference.
This completely messes up the processes I do with the array afterward.
Is that normal behavior ?
How can I avoid it ?
When you pass by reference to a foreach statement, you really should read the docs :)
http://php.net/manual/en/control-structures.foreach.php
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>
Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().
Basically, it's saying that when you pass by ref, it will remain locked on the last item due to an internal pointer.
The second user-comment at 40 points:
"Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()."
I cannot stress this point of the documentation enough! Here is a simple example of exactly why this must be done:
<?php
$arr1 = array("a" => 1, "b" => 2, "c" => 3);
$arr2 = array("x" => 4, "y" => 5, "z" => 6);
foreach ($arr1 as $key => &$val) {}
foreach ($arr2 as $key => $val) {}
var_dump($arr1);
var_dump($arr2);
?>
The output is:
array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> &int(6) }
array(3) { ["x"]=> int(4) ["y"]=> int(5) ["z"]=> int(6) }
Notice how the last index in $arr1 is now the value from the last index in $arr2!
There are more comments which you will find interesting if you look for "reference" in that link.
tl;dr:
It's a bit funny/buggy/weird/un-patched.
Understand what the implications are as you write your code and make space for them.

Fixing multidimensional array

I'm trying to make a multidimensional array that should print out like this (without formatting):
array(3) {
[0]=> array(5) {
[0]=> int(0)
[1]=> string(5) "Arena"
[2]=> string(18) "2012-05-3017:00:00"
[3]=> string(18) "2012-05-3000:00:00"
[4]=> string(33) "Masquerade Checkin (Participants)"
},
[1]=> array(5) {
[0]=> int(0)
[1]=> string(10) "Workshop 1"
[2]=> string(18) "2012-05-3017:00:00"
[3]=> string(18) "2012-05-3000:00:00"
[4]=> string(15) "Death Note (Live)"
},
[2]=> array(5) {
[0]=> int(0)
[1]=> string(7) "Video 6"
[2]=> string(18) "2012-05-3017:00:00"
[3]=> string(18) "2012-05-3000:00:00"
[4]=> string(26) "Takeuchi Fan Panel"
}
}
Notice from the above code that the inner array() length is always 5.
Here is my code below:
$loopsArray = array();
$data=array();
// graphing info come in here.
foreach ($events as $key => $event) {
$el=$event['event_location'] ;
$eln=$event['event_locationName'];
$ed=$event['event_date'];
$es=$event['event_start'];
$ee=$event['event_end'];
$en=$event['event_name'];
array_push($loopsArray,$el,$eln, $ed.$es,$ed.$ee,$en);
array_push($data,$loopsArray);
}
var_dump($data);
Here the print out
array(27) {
[0]=> array(5) {
[0]=> int(0)
[1]=> string(5) "Arena"
[2]=> string(18) "2012-05-3017:00:00"
[3]=> string(18) "2012-05-3000:00:00"
[4]=> string(33) "Masquerade Checkin (Participants)"
}
[1]=> array(10) {
[0]=> int(0)
[1]=> string(5) "Arena"
[2]=> string(18) "2012-05-3017:00:00"
[3]=> string(18) "2012-05-3000:00:00"
[4]=> string(33) "Masquerade Checkin (Participants)"
[5]=> int(13)
[6]=> string(11) "Autograph 1"
[7]=> string(18) "2012-06-2419:00:00"
[8]=> string(18) "2012-06-2422:00:00"
[9]=> string(17) "Parents and Anime"
}
//... continues
}
Notice that the inner arrays length double each iteration. array(5) array(10) array(15)array(20).
It doubles up to 60 elements in the last inner array. Each inner array should only have 5 elements in them. I don't understand why it is doubling or how to fix it.
Can you look over my loop and let me know how to fix it?
I have to use this multidimensional array for this code to work in JpGraph.
TIP : write $loopsArray = array(); inside foreach
better approach
instead of
array_push($loopsArray,$el,$eln, $ed.$es,$ed.$ee,$en);
array_push($data,$loopsArray);
try this
$temp = array ($el,$eln, $ed.$es,$ed.$ee,$en);
$data[] = $temp;

Categories