note 110106 deleted from language.references by googleguy
| From: | googleguy@php.net | 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.