note 110106 deleted from language.references by googleguy

From: Date: Thu, 20 Sep 2012 00:15:10 +0000
Subject: note 110106 deleted from language.references by googleguy
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-190890@lists.php.net to get a copy of this message
Note Submitter: alexandrebr at gmail dot com ---- Although PHP does not allow you to see memory address of the variables, you can "virtually" map these addresses, by analyzing "serialize" output. Its output is really simple to understand: "a" means "Array". "s" means "String". "i" means "Integer". "b" means Bool. The secret is the "R", which means "Reference". So, if you pay attention to the follow serialize output, you can understand how the memory is mapped: <?php echo serialize($someArray); /** a:4:{ // Address '1' s:4:"Key1"; s:7:"Value-1"; // Address '2' s:4:"Key2"; s:7:"Value-2"; // Address '3' s:4:"Key3"; a:2:{ // Address '4' s:8:"Sub-Key1"; s:7:"Value-1"; // Address '5' s:8:"Sub-Key2"; s:7:"Value-2"; // Address '6' } s:4:"Key4"; a:2:{ // Address '7' s:8:"Sub-Key1"; R:5; // Reference to address '5' s:8:"Sub-Key2"; R:6; // Reference to address '6' } } **/ ?> By doing this analysis, you are able to handle all references with little trouble. This allows us to write some functions that may be really useful for all of us: <?php function is_ref_to(&$a, &$b){ $ser = serialize(Array('a'=>&$a, 'b'=>&$b)); return (substr($ser, -6) == ';R:2;}'); } $str = "My sample string"; $equal = "My sample string"; // Not reference, but equal string. $refer = &$str; echo 'Is $STR &= $EQUAL? '.(is_ref_to($str, $equal)?'Yes':'No')."\r\n"; // Will output "No" echo 'Is $STR &= $STR? '.(is_ref_to($str, $str )?'Yes':'No')."\r\n"; // Will output "Yes" echo 'Is $STR &= $REFER? '.(is_ref_to($str, $refer)?'Yes':'No')."\r\n"; // Will output "Yes" echo 'Is $REFER &= $STR? '.(is_ref_to($refer, $str)?'Yes':'No')."\r\n"; // Will output "Yes" // Pay attention that we are actually comparing memory addresses, and NOT the values. ?> The serialize function also allows us to strip all references from an Array(), similar to what "print_r" does, to avoid recursion. <?php function remove_recursion(&$array, $replaceWith){ $ser = serialize($array); $ser = preg_replace("/R:[0-9]+;/", serialize($replaceWith), $ser); return unserialize($ser); } $a = Array(); $a['Main'] = Array('Hello'=>'World'); $a['Clone'] = &$a['Main']; $a['Main']['Ref-To-Clone'] = &$a['Clone']; print_r(remove_recursion($a)); /** This will output: Array( [Main] => Array( [Hello] => World [Ref-To-Clone] => ** Removing references/recursion ** ) [Clone] => ** Removing references/recursion ** ) **/ // IMPORTANT: // --> We're using PREG_REPLACE to replace string, but we are not escaping any variables here. // --> So, we WILL have problems if input is unexpected, like: // $a['String'] = "String containing R:123; inside it."; // --> Or: // remove_recursion($a, "Replace with \$1 or \\1"); // As escaping string are not the focus of this part of the manual, it's up to you how to handle it. ?> This is the most efficient way I found to identify and manipulate references with PHP, and I haven't seen anyone talking about it so far.

« previous php.notes (#190890) next »