wepnop Posted March 3, 2011 Share Posted March 3, 2011 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"); Quote Link to comment Share on other sites More sharing options...
wepnop Posted March 3, 2011 Author Share Posted March 3, 2011 I tested with a normal for, and it goes well. Anyway im willing to know why this happens!? Quote Link to comment Share on other sites More sharing options...
wepnop Posted March 4, 2011 Author Share Posted March 4, 2011 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; } ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.