Jump to content

foreach modifiying data??? exam today, help!


wepnop

Recommended Posts

Im having a very strange problem with no logic for me. Im doing a function that draws a circle with arcs in it based on a array of information.

 

My problem is that the second foreach, that is used to generate the image arc

for each entry in the array, is somewhat modifing the array, so when the it arrives to the second iteration, the next array entry is copied as the second array entry.

 

And im sorry but i just dont see whats going on, no copy methods or nothing here, no?

 

	 
 foreach ($dades as $dada) {

	$col_tmp = imagecolorallocate($img, $dada['color']['r'], $dada['color']['g'], 
									$dada['color']['b']);

	echo 'coltmp' ; iv($col_tmp); echo '<br>';
	echo 'valor' ; iv($dada['valor']); echo '<br>';

	$ang_tmp = calcularAngle($dada['valor'], $total);

	echo 'ang tmp' ; iv($ang_tmp); echo '<br>';

	imagefilledarc($img, $amp_centre, $alt_centre, $alt_cercle,  $amp_cercle, 
					$ang_acum, $ang_tmp + $ang_acum, $col_tmp, IMG_ARC_PIE);

	echo 'ang acum' ; iv($ang_acum); echo '<br>';

	$ang_acum += $ang_tmp;

	unset($col_tmp);
	unset($ang_tmp);

	iv($dades);
 }

 

iv() is my test function, it works like print_r.

 

Here the full code:

 

<?php

include '\lib\test.php';

 

function calcularAngle($cuant,$total) {

return (360*$cuant)/$total;

}

 

$col_fons = array(

'r' => 255,

'g' => 222,

'b' => 198

);

$dades  = array();

$dades[] = array(

'valor' => 24,

'nom' => 78,

);

$dades[] = array(

'valor' => 123,

'nom' => 78,

);

$dades[] = array(

'valor' => 95,

'nom' => 78,

);

$tamany = array(

'altura' => 222,

'amplada' => 222,

 

);

 

dibQuesitos($dades, $col_fons, $tamany);

 

function dibQuesitos($dades, $col_fons, $tamany) {

# dadas es un array de arrays amb el nom de la entrada, la cuantitat a procesar, i

# el color.

 

 

# Ficar valors per defecte si nil.

 

# Si no es pasa res com a color, el color es genera aleatoriament. EL color es un array

# amb els tres valors

 

  //Creamos un cradrado de 200X200 píxeles

$img=imagecreate($tamany['altura'], $tamany['amplada']);

//Ahora le damos color al fondo y al quesito!

$fondo=imagecolorallocate($img, $col_fons['r'], $col_fons['g'], $col_fons['b']);

 

$cont = 10000;

$total = 0;

 

# Primer s'itera sobre les dades per corregir si no tenen colors, o per

# sumar el total dels valors.

foreach ($dades as &$dada) {

 

# Si no te color, creem un aleatoriament. Perque no es puguin repetir,

# el contador com a base per el algoritme generador de colors.

if (! isset($dada['color'])) {

 

$dada['color'] = array();

$seed = microtime() ;

srand((double) $seed * $cont * 10000);

$dada['color']['r'] = rand(0, 255);

srand((double) $seed  * $cont * 20000);

$dada['color']['g'] = rand(0, 255);

srand((double) $seed  * $cont * 30000);

$dada['color']['b'] = rand(0, 255);

 

}

 

$total += $dada['valor'];

 

$cont+=10000;

}

 

 

 

# En la segona iteracio crea els colors, angles i

# dibuixa tot plegat

$colors = array();

$ang_acum = 0;

 

$alt_centre = $tamany['altura']/2;

$amp_centre = $tamany['amplada']/2;

 

$alt_cercle = $tamany['altura'] - $tamany['altura']/8;

$amp_cercle = $tamany['amplada'] - $tamany['amplada']/8;

 

#iv($dades);

 

foreach ($dades as $dada) {

 

$col_tmp = imagecolorallocate($img, $dada['color']['r'], $dada['color']['g'],

$dada['color']['b']);

 

echo 'coltmp' ; iv($col_tmp); echo '<br>';

echo 'valor' ; iv($dada['valor']); echo '<br>';

 

$ang_tmp = calcularAngle($dada['valor'], $total);

 

echo 'ang tmp' ; iv($ang_tmp); echo '<br>';

 

imagefilledarc($img, $amp_centre, $alt_centre, $alt_cercle,  $amp_cercle,

$ang_acum, $ang_tmp + $ang_acum, $col_tmp, IMG_ARC_PIE);

 

echo 'ang acum' ; iv($ang_acum); echo '<br>';

 

$ang_acum += $ang_tmp;

 

unset($col_tmp);

unset($ang_tmp);

 

iv($dades);

}

 

imagepng($img,"imagen.png");

Link to comment
Share on other sites

I found the solution here. I add that you can also use a normal for for it:

 

Krzysztof - ksobolewski at o2 dot pl 09-Jul-2009 11:50
The weird behaviour of references in foreach remains as long as in PHP 5.2.08  (Linux) and PHP 5.2.9 (Windows XP).   The simplest example would be:

<?php
    $a = array('a', 'b','c');
    foreach($a as &$row){
        //you don't have to do anything here
       }
    print_r($a);
    foreach($a as $row){
       echo "<br />".$row;
    }
?>

the result of print_r will be correct - array of ('a','b','c') values. The second foreach, however, would
produce a,b,b. For all arrays, regardless of size, it would be the n-1 element
(the element right before the last one). Eg. for 'a','b','c','d','e','f', the script would produce a,b,c,d,e,e.
There are few solutions to this:

1. safest - avoid using references in foreach;  so instead of
<?php
foreach($a as &$row){
    // do something, eg.
    $row = trim($row);
}
?>

you would use

<?php
foreach($a as $i=>$row){
    // do something on row, eg.
    $row = trim($row);
    // replace the row in the table
    $a[$i]=$row;
}
?>
decrease of performance is the cost, however

2. equally safe and more usable - unset the element reference right after the foreach loop with references, eg.:
<?php
    $a = array('a', 'b','c');
    foreach($a as &$row){
        //you don't have to do anything here
       }
       unset ($row)); // it is safe now to use $row again
    print_r($a);
    foreach($a as $row){
       echo "<br />".$row;
    }
?>

3. use references in both case; it seems that iterations work correct if you use &$row in both loops or don't use it in any:

<?php
    $a = array('a', 'b','c');
    foreach($a as &$row){
        //you don't have to do anything here
       }
       print_r($a);
       // works OK now even without unset($row)
    foreach($a as &$row){
       echo "<br />".$row;
    }
?>

4. use references in foreach only inside functions or methods; outside the function scope it should be safe

<?php
function cleanTable($a){
    foreach($a as &$row){
        $row = trim($row);
    }
}

$a = array('a','b','c');
cleanTable($a);
foreach($a as $row){
echo "<br />".$row;
}
?>

drawbacks: NONE! I Quite contrary, the code looks more tidy.

5. avoid using the same variable names for referenced and non-referenced values; for example, in the first case use &$rRow, and in the second one - $row. It's neither elegant, nor efficient, though, as each new variable lowers the application performance a bit.
<?php
    $a = array('a', 'b','c');
    foreach($a as &$rRow){ // $rRow for 'referenced row'
        //you don't have to do anything here
       }
    print_r($a);

    foreach($a as $row){
       echo "<br />".$row;
    }
?>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.