php-general Digest 8 Jan 2012 15:53:09 -0000 Issue 7640

Topics (messages 316211 through 316219):

Variable Troubleshooting Code
        316211 by: Donovan Brooke
        316212 by: David Courtin

Strange foreach reference issue
        316213 by: Tim Behrendsen
        316214 by: Stephen
        316215 by: Matijn Woudt
        316216 by: Tim Behrendsen
        316217 by: Stephen
        316218 by: Tim Behrendsen
        316219 by: Adi Mutu

Administrivia:

To subscribe to the digest, e-mail:
        php-general-digest-subscr...@lists.php.net

To unsubscribe from the digest, e-mail:
        php-general-digest-unsubscr...@lists.php.net

To post to the list, e-mail:
        php-gene...@lists.php.net


----------------------------------------------------------------------
--- Begin Message ---
Hello!,
I work in another language mostly and often develop while displaying variables (post,get,and defined) and their values at the bottom of the page or in specific places. So, I thought I'd forward my PHP version as an effort of good Karma to the list perhaps! ;-)

Below is 2 simple functions that are helpful for troubleshooting while developing. Just place this code into a .php file and require it at the top of any PHP page. Then, at the bottom of the page, or in a specific (more pertinent) location, call the functions with something like this:

------------
<?PHP
//troubleshooting code
print '<br /><b>Testing:</b><p>';
                
print htmlentities(list_formvars());
                
print htmlentities(list_vars(get_defined_vars()));
                
print '</p>';
?>
-------------

Optionally, you can call only specific naming conventions of your variables (if you use them).. ie:

print htmlentities(list_vars(get_defined_vars(),'t_'));

The above will display all defined vars such as:

t_name=<value>
t_city=<value>
t_address=<value>

etc..


Code:
-----------------------------------
/*
FUNCTION NAME: list_formvars
   INPUT: optional <begins with> var
   OUTPUT: <Name> = <Value> <br />
         <Name> = <Value> <br />
   USE: For troubleshooting code

   Example Use:
      list_formvars();
      list_formvars('f_a');

*/function list_formvars($pmatch = null) {
   print "<br /><b>'get' Vars:</b><br />";
   foreach ($_GET as $key => $value) {
            if (isset($pmatch)) {
               if (substr($key,0,strlen($pmatch)) == $pmatch) {
                  print "$key = $value<br />";
               }
            } else {
               print "$key = $value<br />";
            }
         }

   print "<br /><b>'post' Vars:</b><br />";
   foreach ($_POST as $key => $value) {
            if (isset($pmatch)) {
               if (substr($key,0,strlen($pmatch)) == $pmatch) {
                  print "$key = $value<br />";
               }
            } else {
               print "$key = $value<br />";
            }
         }
}/*
FUNCTION NAME: list_vars
   INPUT: get_defined_vars(),<begins with> match
   OUTPUT: <Name> = <Value> <br />
         <Name> = <Value> <br />
   USE: For troubleshooting code

   Example Use:
      list_vars(get_defined_vars());
      list_vars(get_defined_vars(),'t_');
*/function list_vars($a_vars,$pmatch = null) {
      print "<br /><b>'defined' Vars:</b><br />";
         foreach ($a_vars as $key => $value) {
            if (isset($pmatch)) {
               if (substr($key,0,strlen($pmatch)) == $pmatch) {
                  print "$key = $value<br />";
               }
            } else {
               print "$key = $value<br />";
            }
         }
}
------------------------------------------------

Cheers,
Donovan


P.S. Always open to good criticism if you peeps see something that can be written better.. this is about my 3rd PHP project only... so, still heavily learning ;-)


--
D Brooke

--- End Message ---
--- Begin Message ---
Hi,

some pretty natives php functions exists to do the job :
var_export — Outputs or returns a parsable string representation of a variable
debug_zval_dump — Dumps a string representation of an internal zend value to 
output
var_dump — Dumps information about a variable
print_r — Prints human-readable information about a variable

echo '<pre>';
print_r( array | object );
echo '</pre>';  

Regards.


Le 7 janv. 2012 à 19:00, Donovan Brooke a écrit :

> Hello!,
> I work in another language mostly and often develop while displaying 
> variables (post,get,and defined) and their values at the bottom of the page 
> or in specific places. So, I thought I'd forward my PHP version as an effort 
> of good Karma to the list perhaps! ;-)
> 
> Below is 2 simple functions that are helpful for troubleshooting while 
> developing. Just place this code into a .php file and require it at the top 
> of any PHP page. Then, at the bottom of the page, or in a specific (more 
> pertinent) location, call the functions with something like this:
> 
> ------------
> <?PHP
> //troubleshooting code
> print '<br /><b>Testing:</b><p>';
>               
> print htmlentities(list_formvars());
>               
> print htmlentities(list_vars(get_defined_vars()));
>               
> print '</p>';
> ?>
> -------------
> 
> Optionally, you can call only specific naming conventions of your variables 
> (if you use them).. ie:
> 
> print htmlentities(list_vars(get_defined_vars(),'t_'));
> 
> The above will display all defined vars such as:
> 
> t_name=<value>
> t_city=<value>
> t_address=<value>
> 
> etc..
> 
> 
> Code:
> -----------------------------------
> /*
> FUNCTION NAME: list_formvars
>   INPUT: optional <begins with> var
>   OUTPUT: <Name> = <Value> <br />
>         <Name> = <Value> <br />
>   USE: For troubleshooting code
> 
>   Example Use:
>      list_formvars();
>      list_formvars('f_a');
> 
> */function list_formvars($pmatch = null) {
>   print "<br /><b>'get' Vars:</b><br />";
>   foreach ($_GET as $key => $value) {
>            if (isset($pmatch)) {
>               if (substr($key,0,strlen($pmatch)) == $pmatch) {
>                  print "$key = $value<br />";
>               }
>            } else {
>               print "$key = $value<br />";
>            }
>         }
> 
>   print "<br /><b>'post' Vars:</b><br />";
>   foreach ($_POST as $key => $value) {
>            if (isset($pmatch)) {
>               if (substr($key,0,strlen($pmatch)) == $pmatch) {
>                  print "$key = $value<br />";
>               }
>            } else {
>               print "$key = $value<br />";
>            }
>         }
> }/*
> FUNCTION NAME: list_vars
>   INPUT: get_defined_vars(),<begins with> match
>   OUTPUT: <Name> = <Value> <br />
>         <Name> = <Value> <br />
>   USE: For troubleshooting code
> 
>   Example Use:
>      list_vars(get_defined_vars());
>      list_vars(get_defined_vars(),'t_');
> */function list_vars($a_vars,$pmatch = null) {
>      print "<br /><b>'defined' Vars:</b><br />";
>         foreach ($a_vars as $key => $value) {
>            if (isset($pmatch)) {
>               if (substr($key,0,strlen($pmatch)) == $pmatch) {
>                  print "$key = $value<br />";
>               }
>            } else {
>               print "$key = $value<br />";
>            }
>         }
> }
> ------------------------------------------------
> 
> Cheers,
> Donovan
> 
> 
> P.S. Always open to good criticism if you peeps see something that can be 
> written better.. this is about my 3rd PHP project only... so, still heavily 
> learning ;-)
> 
> 
> -- 
> D Brooke
> 
> -- 
> PHP General Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
> 


--- End Message ---
--- Begin Message ---
Hello,

This sure looks like a bug, but maybe there's some subtlety going on that I don't understand, so I would appreciate some insight. After much debugging, I tracked down a bug in my code to this test program. My PHP version is 5.3.3, running under Fedora Linux.

<?php
    $row_list = array(
        array(
            'Title' => 'Title #1',
        ),
        array(
            'Title' => 'Title #2',
        ),
        array(
            'Title' => 'Title #3',
        ) );

    print "   Rows at start: " . print_r($row_list, true);
    foreach ($row_list as $idx => &$row) {
        print "Title A $idx: {$row['Title']}\n";
    }

    print "   Rows are now: " . print_r($row_list, true);
    foreach ($row_list as $idx => $row) {
        print "Title B $idx: {$row['Title']}\n";
    }
?>

When you run the program, it gives the following output:

------------------------------------------
   Rows at start: Array
(
    [0] => Array
        (
            [Title] => Title #1
        )

    [1] => Array
        (
            [Title] => Title #2
        )

    [2] => Array
        (
            [Title] => Title #3
        )

)
Title A 0: Title #1
Title A 1: Title #2
Title A 2: Title #3
   Rows are now: Array
(
    [0] => Array
        (
            [Title] => Title #1
        )

    [1] => Array
        (
            [Title] => Title #2
        )

    [2] => Array
        (
            [Title] => Title #3
        )

)
Title B 0: Title #1
Title B 1: Title #2
Title B 2: Title #2
------------------------------------------

Note that the second foreach repeats the second row, even though the index is correct and the print_r shows things as correct.

Now, if you change the name of the reference variable from '$row' to '$rowx' (for example), things will work. So clearly there's some issue with $row being previously used as a reference that's "contaminating" the subsequent use of $row in the foreach. If there's some logic to this, it's escaping me.

Any insight on this would be appreciated.

Regards,

Tim Behrendsen




--- End Message ---
--- Begin Message ---
I cut and pasted your code and got the same result.

I flipped the two foreach blocks and got the expected results.

I deleted the first block and copied the second, then updated the string. I got this. I can't explain.

<?php
    $row_list = array(
        array(
            'Title' => 'Title #1',
        ),
        array(
            'Title' => 'Title #2',
        ),
        array(
            'Title' => 'Title #3',
        ) );

  print "   Rows are: " . print_r($row_list, true);
    foreach ($row_list as $idx => $row) {
        print "Title A $idx: {$row['Title']}\n";
    }

  print "   Rows are now: " . print_r($row_list, true);
    foreach ($row_list as $idx => $row) {
        print "Title B $idx: {$row['Title']}\n";
    }

   Rows are: Array
(
    [0] =>  Array
        (
            [Title] =>  Title #1
        )

    [1] =>  Array
        (
            [Title] =>  Title #2
        )

    [2] =>  Array
        (
            [Title] =>  Title #3
        )

)
Title A 0: Title #1
Title A 1: Title #2
Title A 2: Title #3
   Rows are now: Array
(
    [0] =>  Array
        (
            [Title] =>  Title #1
        )

    [1] =>  Array
        (
            [Title] =>  Title #2
        )

    [2] =>  Array
        (
            [Title] =>  Title #3
        )

)
Title B 0: Title #1
Title B 1: Title #2
Title B 2: Title #3



On 12-01-07 06:29 PM, Tim Behrendsen wrote:
Hello,

This sure looks like a bug, but maybe there's some subtlety going on that I don't understand, so I would appreciate some insight. After much debugging, I tracked down a bug in my code to this test program. My PHP version is 5.3.3, running under Fedora Linux.

<?php
    $row_list = array(
        array(
            'Title' => 'Title #1',
        ),
        array(
            'Title' => 'Title #2',
        ),
        array(
            'Title' => 'Title #3',
        ) );

    print "   Rows at start: " . print_r($row_list, true);
    foreach ($row_list as $idx => &$row) {
        print "Title A $idx: {$row['Title']}\n";
    }

    print "   Rows are now: " . print_r($row_list, true);
    foreach ($row_list as $idx => $row) {
        print "Title B $idx: {$row['Title']}\n";
    }
?>

When you run the program, it gives the following output:

------------------------------------------
   Rows at start: Array
(
    [0] => Array
        (
            [Title] => Title #1
        )

    [1] => Array
        (
            [Title] => Title #2
        )

    [2] => Array
        (
            [Title] => Title #3
        )

)
Title A 0: Title #1
Title A 1: Title #2
Title A 2: Title #3
   Rows are now: Array
(
    [0] => Array
        (
            [Title] => Title #1
        )

    [1] => Array
        (
            [Title] => Title #2
        )

    [2] => Array
        (
            [Title] => Title #3
        )

)
Title B 0: Title #1
Title B 1: Title #2
Title B 2: Title #2
------------------------------------------

Note that the second foreach repeats the second row, even though the index is correct and the print_r shows things as correct.

Now, if you change the name of the reference variable from '$row' to '$rowx' (for example), things will work. So clearly there's some issue with $row being previously used as a reference that's "contaminating" the subsequent use of $row in the foreach. If there's some logic to this, it's escaping me.

Any insight on this would be appreciated.

Regards,

Tim Behrendsen






--- End Message ---
--- Begin Message ---
On Sun, Jan 8, 2012 at 12:29 AM, Tim Behrendsen <t...@behrendsen.com> wrote:
> Hello,
>
> This sure looks like a bug, but maybe there's some subtlety going on that I
> don't understand, so I would appreciate some insight. After much debugging,
> I tracked down a bug in my code to this test program. My PHP version is
> 5.3.3, running under Fedora Linux.
>
> <?php
>    $row_list = array(
>        array(
>            'Title' => 'Title #1',
>        ),
>        array(
>            'Title' => 'Title #2',
>        ),
>        array(
>            'Title' => 'Title #3',
>        ) );
>
>    print "   Rows at start: " . print_r($row_list, true);
>    foreach ($row_list as $idx => &$row) {

Why is there an '&' before $row here? That seems like the problem to me..

Matijn

--- End Message ---
--- Begin Message ---
On 1/7/2012 4:18 PM, Matijn Woudt wrote:
On Sun, Jan 8, 2012 at 12:29 AM, Tim Behrendsen<t...@behrendsen.com>  wrote:
Hello,

This sure looks like a bug, but maybe there's some subtlety going on that I
don't understand, so I would appreciate some insight. After much debugging,
I tracked down a bug in my code to this test program. My PHP version is
5.3.3, running under Fedora Linux.

<?php
    $row_list = array(
        array(
            'Title' =>  'Title #1',
        ),
        array(
            'Title' =>  'Title #2',
        ),
        array(
            'Title' =>  'Title #3',
        ) );

    print "   Rows at start: " . print_r($row_list, true);
    foreach ($row_list as $idx =>  &$row) {
Why is there an '&' before $row here? That seems like the problem to me..

Matijn

When you use an ampersand on the variable, that creates a reference to the array elements, allowing you to potentially change the array elements themselves (which I'm not doing here).

http://www.php.net/manual/en/control-structures.foreach.php

I do notice in the manual that it says, "Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()." But that doesn't really explain why it contaminates the next foreach loop in such an odd way. You would think that the $row in the second loop would be assigned a non-reference value.

Tim

--- End Message ---
--- Begin Message ---
On 12-01-07 07:30 PM, Tim Behrendsen wrote:

When you use an ampersand on the variable, that creates a reference to the array elements, allowing you to potentially change the array elements themselves (which I'm not doing here).

http://www.php.net/manual/en/control-structures.foreach.php

I do notice in the manual that it says, "Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()." But that doesn't really explain why it contaminates the next foreach loop in such an odd way. You would think that the $row in the second loop would be assigned a non-reference value.

Tim

Tim,

You are using the &$variable in an unintended (by PHP designers), and I suggest undefined manner.

So the outcome cannot, but definition be explained.

Was this intended, and what were you trying to accomplish?

Stephen

--- End Message ---
--- Begin Message ---
On 1/7/2012 4:44 PM, Stephen wrote:
On 12-01-07 07:30 PM, Tim Behrendsen wrote:

When you use an ampersand on the variable, that creates a reference to the array elements, allowing you to potentially change the array elements themselves (which I'm not doing here).

http://www.php.net/manual/en/control-structures.foreach.php

I do notice in the manual that it says, "Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()." But that doesn't really explain why it contaminates the next foreach loop in such an odd way. You would think that the $row in the second loop would be assigned a non-reference value.

Tim

Tim,

You are using the &$variable in an unintended (by PHP designers), and I suggest undefined manner.

So the outcome cannot, but definition be explained.

Was this intended, and what were you trying to accomplish?

Stephen

In the real code, I just happen to use the same variable name first as a reference, and then as a normal non-reference, and was getting the mysterious duplicate rows.

I think I'm using everything in a completely reasonable way; the second foreach is reassigning the loop variable. Nothing that comes before using that variable ought to cause undefined behavior. The warning in the manual is about using the loop variable as a reference after exiting the loop, but I'm not doing that. I'm reassigning it, exactly as if I just decided to do a straight assignment of "$row"....

Ah ha, wait a minute, that's the key. OK, this is making more sense.

The first loop is leaving a reference to the final element. But then the second foreach is doing a straight assignment to the $row variable, but $row is a reference to the final element. So the foreach is assigning its iterated value to the final element of the array, instead of a normal variable.

OK, I understand the logic now. The world now makes sense. The moral is always unset the iterator variable when doing foreach with a reference, like the manual says. :)

Thanks for everyone's help.

Tim

--- End Message ---
--- Begin Message ---
You can see here some nice pics, it's exactly as you said.

http://schlueters.de/blog/archives/141-References-and-foreach.html



________________________________
 From: Tim Behrendsen <t...@behrendsen.com>
To: php-gene...@lists.php.net 
Cc: Stephen <stephe...@rogers.com>; Matijn Woudt <tijn...@gmail.com> 
Sent: Sunday, January 8, 2012 3:01 AM
Subject: Re: [PHP] Strange foreach reference issue
 
On 1/7/2012 4:44 PM, Stephen wrote:
> On 12-01-07 07:30 PM, Tim Behrendsen wrote:
>> 
>> When you use an ampersand on the variable, that creates a reference to the 
>> array elements, allowing you to potentially change the array elements 
>> themselves (which I'm not doing here).
>> 
>> http://www.php.net/manual/en/control-structures.foreach.php
>> 
>> I do notice in the manual that it says, "Reference of a $value and the last 
>> array element remain even after the foreach loop. It is recommended to 
>> destroy it by unset()." But that doesn't really explain why it contaminates 
>> the next foreach loop in such an odd way. You would think that the $row in 
>> the second loop would be assigned a non-reference value.
>> 
>> Tim
>> 
> Tim,
> 
> You are using the &$variable in an unintended (by PHP designers), and I 
> suggest undefined manner.
> 
> So the outcome cannot, but definition be explained.
> 
> Was this intended, and what were you trying to accomplish?
> 
> Stephen

In the real code, I just happen to use the same variable name first as a 
reference, and then as a normal non-reference, and was getting the mysterious 
duplicate rows.

I think I'm using everything in a completely reasonable way; the second foreach 
is reassigning the loop variable. Nothing that comes before using that variable 
ought to cause undefined behavior. The warning in the manual is about using the 
loop variable as a reference after exiting the loop, but I'm not doing that. 
I'm reassigning it, exactly as if I just decided to do a straight assignment of 
"$row"....

Ah ha, wait a minute, that's the key. OK, this is making more sense.

The first loop is leaving a reference to the final element. But then the second 
foreach is doing a straight assignment to the $row variable, but $row is a 
reference to the final element. So the foreach is assigning its iterated value 
to the final element of the array, instead of a normal variable.

OK, I understand the logic now. The world now makes sense. The moral is always 
unset the iterator variable when doing foreach with a reference, like the 
manual says. :)

Thanks for everyone's help.

Tim

-- PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

--- End Message ---

Reply via email to