note 110106 added to language.references
| From: | alexandrebr at gmail dot com | Date: | Wed, 19 Sep 2012 19:57:26 +0000 |
| Subject: | note 110106 added to language.references | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-190886@lists.php.net to get a copy of this message | ||
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.
----
Server IP: 69.147.83.197
Probable Submitter: 189.115.46.132
----
Manual Page -- http://www.php.net/manual/en/language.references.php
Edit -- https://master.php.net/note/edit/110106
Del: integrated -- https://master.php.net/note/delete/110106/integrated
Del: useless -- https://master.php.net/note/delete/110106/useless
Del: bad code -- https://master.php.net/note/delete/110106/bad+code
Del: spam -- https://master.php.net/note/delete/110106/spam
Del: non-english -- https://master.php.net/note/delete/110106/non-english
Del: in docs -- https://master.php.net/note/delete/110106/in+docs
Del: other reasons-- https://master.php.net/note/delete/110106
Reject -- https://master.php.net/note/reject/110106
Search -- https://master.php.net/manage/user-notes.php