PHP: Ссылки. Разъяснения - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Что делают ссылки Exceptions

Last updated: Fri, 26 Jan 2007

view this page in

# Глава 21. Ссылки. Разъяснения

# Что такое ссылки

Ссылки в PHP - это средство доступа к содержимому одной переменной под разными именами. Они не похожи на указатели C и не являются псевдонимами таблицы символов. В PHP имя переменной и её содержимое - это разные вещи, поэтому одно содержимое может иметь разные имена. Ближайшая аналогия - имена файлов Unix и файлы - имена переменных являются элементами каталогов, а содержимое переменных это сами файлы. Ссылки в PHP - аналог жёстких ссылок (hardlinks) в файловых системах Unix.

add a note User Contributed Notes
Ссылки. Разъяснения
sneskid at hotmail dot com
06-Mar-2007 12:47
`(v5.1.4)
One cool thing about var_dump is it shows which variables are references (when dumping arrays), symbolized by '∫' for int/null, and by '&' for boolean/double/string/array/object. I don't know why the difference in symmmmbolism.
After playing around I found a better way to implement detaching (twas by accident). var_dump can show what's going on.
<?php
function &detach($v=null){return $v;}
$A=array('x' => 123, 'y' => 321);
$A['x'] = &$A['x'];
var_dump($A);
/* x became it's own reference...
array(2) {
["x"]=> ∫(123)
["y"]=> int(321)
}*/
$A['y']=&$A['x'];
var_dump($A);
/* now both are references
array(2) {
["x"]=> ∫(123)
["y"]=> ∫(123)
}*/
$z = 'hi';
$A['y']=&detach(&$z);
var_dump($A);
/* x is still a reference, y and z share
array(2) {
["x"]=> ∫(123)
["y"]=> &string(2) "hi"
}*/
$A['x'] = $A['x'];
$A['y']=&detach();
var_dump($A,$z);
/* x returned to normal, y is on its own, z is still "hi"
array(2) {
["x"]=> int(123)
["y"]=> NULL
}*/
?>
For detach to work you need to use '&' in the function declaration, and every time you call it.
Use this when you know a variable is a reference, and you want to assign a new value without effecting other vars referencing that piece of memory. You can initialize it with a new constant value, or variable, or new reference all in once step.`
sneskid at hotmail dot com
31-Oct-2006 09:33
`in addition to what 'jw at jwscripts dot com' wrote about unset; it can also be used to "detach" the variable alias so that it may work on a unique piece of memory again.
here's an example
<?php
define('NL', "\r\n");
$v1 = 'shared';
$v2 = &$v1;
$v3 = &$v2;
$v4 = &$v3;
echo 'before:'.NL;
echo 'v1=' . $v1 . NL;
echo 'v2=' . $v2 . NL;
echo 'v3=' . $v3 . NL;
echo 'v4=' . $v4 . NL;
// detach messy
$detach = $v1;
unset($v1);
$v1 = $detach;
// detach pretty, but slower
eval(detach('$v2'));
$v1 .= '?';
$v2 .= ' no more';
$v3 .= ' sti';
$v4 .= 'll';
echo NL.'after:'.NL;
echo 'v1=' . $v1 . NL;
echo 'v2=' . $v2 . NL;
echo 'v3=' . $v3 . NL;
echo 'v4=' . $v4 . NL;
function detach($v) {
$e = '$detach = ' . $v . ';';
$e .= 'unset('.$v.');';
$e .= $v . ' = $detach;';
return $e;
}
?>
output {
before:
v1=shared
v2=shared
v3=shared
v4=shared
after:
v1=shared?
v2=shared no more
v3=shared still
v4=shared still
}
http://www.obdev.at/developers/articles/00002.html says there's no such thing as an "object reference" in PHP, but with detaching it becomes possible.
Hopefully detach, or something like it, will become a language construct in the future.`
gunter dot sammet at gmail dot com
09-Aug-2006 01:23
`I tried to create an array with n depth using a recursive function passing array references around. So far I haven't had much luck and I couldn't find anything on the web. So I ended up using eval() and it seems to work well:
<?php
foreach(array_keys($this->quantity_array) AS $key){
if($this->quantity_array[$key] > 0){
$combinations = explode('-', $key);
$eval_string = '$eval_array';
foreach(array_keys($combinations) AS $key2){
$option_key_value = explode('_', $combinations[$key2]);
$eval_string .= '['.$option_key_value[0].']['.$option_key_value[1].']';
}
$eval_string .= ' = '.$this->quantity_array[$key].';';
eval($eval_string);
}
}
?>
This produces an n dimensional array that will be available in the $eval_array variable. Hope it helps somebody!`
Xor
02-Mar-2006 07:43
`if given little - passing an array by reference slower than by value,
but not if it is necessary to process much data.
function test_ref(&$arr) {
$size = sizeof($arr);
for($n=0; $n<$size; $n++) {
$x .= $arr[$n];
}
return $x;
}
function test_val($arr) {
$size = sizeof($arr);
for($n=0; $n<$size; $n++) {
$x .= $arr[$n];
}
return $x;
}
// fill array
for($n=0; $n<500000; $n++) {
$ar[] = "test".$n;
}
$Bs = array_sum(explode(' ', microtime()));
test_ref($ar);
echo "<br />The function using a reference took ".(array_sum(explode(' ', microtime()))-$Bs);
$Bs = array_sum(explode(' ', microtime()));
test_val($ar);
echo "<br />The funktion using a value took: ".(array_sum(explode(' ', microtime()))-$Bs);
The function using a reference took 10.035583019257
The funktion using a value took: 10.531390190125`
Ed
22-Jan-2006 11:29
`Responding to Slava Kudinov. The only reason why your script takes longer when you pass by reference is that you do not at all modify the array that your passing to your functions. If you do that the diffrences in execution time will be a lot smaller. In fact passing by reference will be faster if just by a little bit.`
Slava Kudinov <skudinov gmail com>
22-Jan-2006 02:01
`In addition to the "array vs &array" example below, php 5.1.2. It seems passing an array by reference slower than by value, consider:
<?php
function test_ref(&$arr) {
$size = sizeof($arr);
for($n=0; $n<$size; $n++) {
$x = 1;
}
}
function test_val($arr) {
$size = sizeof($arr);
for($n=0; $n<$size; $n++) {
$x = 1;
}
}
// fill array
for($n=0; $n<2000; $n++) {
$ar[] = "test".$n;
}
$time = microtime();
test_ref($ar);
echo "<br />The function using a reference took ".(microtime() - $time)." s";
$time = microtime();
test_val($ar);
echo "<br />The funktion using a value took: ".(microtime() - $time)." s";
echo "<br />Done";
?>
output:
The function using a reference took 0.002694 s
The funktion using a value took: 0.000847 s`
cesoid at yahoo dot com
10-Dec-2005 06:28
`Responding to post from nathan (who was responding to iryoku).
It is important to note the difference between what php is doing from the programmer's point of view and what it is doing internally. The note that nathan refers to, about how (for example) $something = $this makes a "copy" of the current object, is talking about making a "copy" from the programmer's perspective. That is, for the programmer, for all practical purposes, $something is a copy, even if internally nothing has been copied yet. For example, changing the data in member $something->somethingVar will not change your current object's data (i.e. it will not change $this->somethingVar).
What it does internally is a totally different story. I've tested "copying" an object which contains a 200,000 element array, it takes almost no time at all until you finally change something in one of the copies, because internally it only makes the copy when it becomes necessary. The original assignment takes less than a millisecond, but when I alter one of the copies, it takes something like a quarter of a second. But this only happens if I alter the 200,000 element array, if I alter a single integer of the object, it takes less than a microsecond again, so the interpretter seems to be smart enough to make copies of some of the objects variables and not others.
The result is that when you change a function to pass by reference, it will only become more efficient if, inside the function, the passed variable is having its data altered, in which case passing by reference causes your code to alter the data of the original copy. If you are passing an object and calling a function in that object, that function may alter the object without you even knowing, which means that you should pass an object by reference as long as it is ok for the original copy to be effected by what you do with the object inside the function.
I think the real moral of the story is this:
1) Pass by reference anything that should refer to and affect the original copy.
2) Pass not by reference things that will definitely not be altered in the function (for an object, it may be impossible to know whether it alters itself upon calling one of its functions).
3) If something needs to be altered inside a function without effecting the original copy, pass it not by reference, and pass the smallest practical part that needs to change, rather than passing, for example, a huge array of which one little integer will be altered.
Or a shorter version: Only pass things by reference when you need to refer to the original copy! (And don't pass huge arrays or long strings when you need to change just a small part of them!)`
mramirez (at) star (minus) dev (dot) com
12-Oct-2005 09:10
`For php programmers that come from pascal,
in object pascal (delphi),
variable references are used with the "absolute" keyword.
PHP example:
<?php
global $myglobal;
$myglobal = 5;
function test()
{
global $myglobal;
/*local*/ $mylocal =& $myglobal;
echo "local: " . $mylocal . "\n";
echo "gloal: " . $myglobal . "\n";
}
test();
?>
Pascal example:
program dontcare;
var myglobal: integer;
procedure test;
var mylocal ABSOLUTE myglobal;
begin
write("local: ", mylocal);
write("global: ", myglobal);
end;
begin
myglobal := 5;
test;
end.
By the way, a "local" keyword in php for local variables,
could be welcome :-)`
y007pig at yahoo dot com dot cn
06-Oct-2005 11:02
`In reply to pike at kw dot nl, '&' is only apply to PHP 4.
PHP 5 changed the behavior and the object is defaultly passed by references and if you turn on E_STRICT, you will get a notice:
Strict Standards: Assigning the return value of new by reference is deprecated in xxxx
If you want to *copy* object in PHP 5, use object clone.`
pike at kw dot nl
01-Oct-2005 06:08
`if your object seems to "forget" assignments you make after instantiation, realize that in
$foo = new Bar()
the variable on the left hand is a *copy* of the variable on the right hand. As a result, & references made during instantiation may point to the righthandside version of Bar() and not to $foo. you'd better use
$foo = & new Bar()`
php at REMOVEMEkennel17 dot co dot uk
23-Aug-2005 06:56
`I found a very useful summary of how references work in PHP4 (and some of the common pitfalls) in this article: http://www.obdev.at/developers/articles/00002.html
It deals with some subtle situations and I recommend it to anyone having difficulty with their references.`
grayson at uiuc dot edu
12-Aug-2005 08:59
`I found a subtle feature of references that caused a bug in one of my PHP applications. In short, if an object passes one of its members to an external function that takes a reference as an argument, the external function can turn that member into a reference to an anonymous point in memory.
Why is this a problem? Later, when you copy the object with $a = $b, the copy and the original share memory.
Solution: If you want to have a function that uses references to modify a member of your object, your object should never pass the member to the function directly. It should first make a copy of the member. Then give that copy to the function. Then copy the new value of that copy in to your original object member.
Below is some code that can reporoduce the this feature and demonstrate the workaround.
function modify1 ( &$pointer_obj ){
$pointer_obj->property = 'Original Value';
}
function modify2 ( &$pointer_obj ){
$newObj->property = 'Original Value';
$pointer_obj = $newObj;
}
class a {
var $i; # an object with properties
function corrupt1(){
modify1 ($this->i);
}
function doNotCorrupt1(){
$tmpi = $this->i;
modify1 ($tmpi);
$this->i = $tmpi;
}
function corrupt2(){
modify2 ($this->i);
}
function doNotCorrupt2(){
$tmpi = $this->i;
modify2 ($tmpi);
$this->i = $tmpi;
}
}
$functions = array ('corrupt1', 'corrupt2', 'doNotCorrupt1', 'doNotCorrupt2');
foreach ($functions as $func){
$original = new a;
### Load some data in to the orginal with one of the four $functions
$original->$func();
$copy = $original;
$copy->i->property = "Changed after the copy was made.";
echo "\n{$func}: \$original->i->property = '" . $original->i->property . "'";
}
The script generates output:
corrupt1: $original->i->property = 'Changed after the copy was made.'
corrupt2: $original->i->property = 'Changed after the copy was made.'
doNotCorrupt1: $original->i->property = 'Original Value'
doNotCorrupt2: $original->i->property = 'Original Value'`
rlynch at lynchmarks dot com
17-May-2005 02:51
`And, further...
<?php
$intSize = sizeof($arrData);
for($i = 0; $i < $intSize; $n++) {
// Do stuff
}
?>
Can be shortened even further by using the often overlooked 'decrement until zero' concept. I don't much like decrementing to get a job done, but it can make a lot of sense when the evaluation-of-doneness is time-costly:
<?php
for($i = sizeof($arrData); $i-- > 0 ; ) {
// Do stuff
}
?>
One less variable to toss on the heap. NOTE that rather inconveniently, the $i goes to and hits zero only in the case where it starts out positive. When it is zero to begin with, it will become -1. Bug or feature? I've used it as a feature as a quick test of whether the $arrData array was empty to begin with. If you don't plan on using $i after the loop for anything, it makes no difference.
If you need to be doing something ascending-sequential though, then the temporary variable suggestions that others have made makes the most sense.
Finally (and important) ... if the $arrData array is somehow being dynamically modified in size due to the //Do-Stuff routine underneath, then you may have little-to-no recourse except to use the sizeof() method/function in the loop. Or, keep up the temporary variable in the loop as you push and pop things into and off the array.
(sigh... this is the notable failing of deeply linked internal data structures: to figure out the size of any linked list of arbitrarily composed elements, the entire array needs to be "walked" every time the sizeof() or count() method is used. But compared to the flexibility of associative arrays, the cost is mitigated by careful use.)
GoatGuy`
nslater at gmail dot com
15-Mar-2005 07:12
`In addition to the note made by "Francis dot a at gmx dot net" you should not normally be using a function such as sizeof() or count() in a control structure such as FOR because the same value is being calculated repeatedly for each iteration. This can slow things down immensely, regardless of whether you pass by value or reference.
It is generally much better to calculate the static values before the defining the looping control structure.
Example:
<?php
$intSize = sizeof($arrData);
for($i = 0; $i < $intSize; $n++) {
// Do stuff
}
?>`
Carlos
14-Mar-2005 12:09
`in the example below, you would get the same result if you change the function to something like:
function test_ref(&$arr) {
$time = time();
$size = sizeof($arr); // <--- this makes difference...
for($n=0; $n<$size; $n++) {
$x = 1;
}
echo "<br />The function using a reference took ".(time() - $time)." s";
}`
Francis dot a at gmx dot net
09-Feb-2005 10:53
`I don't know if this is a bug (I'm using PHP 5.01) but you should be careful when using references on arrays.
I had a for-loop that was incredibly slow and it took me some time to find out that most of the time was wasted with the function sizeof() at every loop, and even more time I spent finding out that this problem it must be somehow related to the fact, that I used a reference of the array. Take a look at the following example:
function test_ref(&$arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />The function using a reference took ".(time() - $time)." s";
}
function test_val($arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />The funktion using a value took: ".(time() - $time)." s";
}
// fill array
for($n=0; $n<2000; $n++) {
$ar[] = "test".$n;
}
test_ref($ar);
test_val($ar);
echo "<br />Done";
When I tested it, the first function was done after 9 seconds, while the second (although the array must be copied) was done in not even one.
The difference is inproportional smaller when the array size is reduced:
When using 1000 loops the first function was running for 1 second, when using 4000 it wasn't even done after 30 Seconds.`
jw at jwscripts dot com
16-Oct-2004 05:18
`Re-using variables which where references before, without unsetting them first, leads to unexpected behaviour.
The following code:
<?php
$numbers = array();
for ($i = 1; $i < 4; $i++) {
$numbers[] = null;
$num = count($numbers);
$index =& $numbers[$num ? $num - 1 : $num];
$index = $i;
}
foreach ($numbers as $index) {
print "$index\n";
}
?>
Does not produce:
1
2
3
But instead:
1
2
2
Applying unset($index) before re-using the variable fixes this and the expected list will be produced:
1
2
3`
hkmaly at bigfoot dot com
15-Sep-2004 08:11
`It seems like PHP has problems with references, like that it can't work properly with circular references or free properly structure with more references. See http://bugs.php.net/?id=30053.
I have big problem with this and I hope someone from PHP add proper warning with explanation IN manual, if they can't fix it.`
jlaing at gmail dot com
17-Jul-2004 08:28
`While trying to do object references with the special $this variable I found that this will not work:
class foo {
function bar() {
...
$this =& $some_other_foo_obj;
}
}
If you want to emulate this functionality you must iterate through the vars of the class and assign references like this:
$vars = get_class_vars('foo');
foreach (array_keys($vars) as $field) {
$this->$field =& $some_other_foo_obj->$field;
}
Now if you modify values within $this they will be modified within $some_other_foo_obj and vice versa.
Hope that helps some people!
p.s.
developer at sirspot dot com's note about object references doesn't seem correct to me.
$temp =& $object;
$object =& $temp->getNext();
Does the same exact thing as:
$object =& $object->getNext();
when you refernce $temp to $object all it does is make $temp an alias to the same memory as $object, so doing $temp->getNext(); and $object->getNext(); are calling the same function on the same object. Try it out if you don't believe me.`
thenewparadigm at hotmail dot com
07-May-2004 12:33
`one very useful aspect for reference that i don't think i saw documented was the ability to skip a few steps with objects stored in objects.
for example:
assuming the object structure is correctly constructed (and mind you i haven't tried this in php, but it does work in most other high-end programming languages), instead of using this structure to get a variable/function
//start
$obj1 -> obj2 -> obj3 -> varX = 0;
$obj1 -> obj2 -> obj3 -> varY = 0;
$obj1 -> obj2 -> obj3 -> functionX();
$obj1 -> obj2 -> obj3 -> functionY();
//end
you can use this method:
//start
$tempObj = & $obj1 -> obj2 -> obj3;
$tempObj -> varX = 0;
$tempObj -> varY = 0;
$tempObj -> functionX();
$tempObj -> functionY();
//end
note, if you want to use a shortcut variable to modify the original object you must include the ampersand (&) to reference the variable, otherwise if you used this line of code
//start
$tempObj = $obj1 -> obj2 -> obj3;
//end
any changes you make to $tempObj will not change the original object and may compromise the object structure, not to mention that it takes up extra memory. however, if you are just using the shortcut variable for read-only purposes, not using a reference wont cause any problems.
another alternative in programming languages is the 'with' structure as seen below
//start
with($obj1 -> obj2 -> obj3) {
varX = 0;
varY = 0;
functionX();
functionY();
}
//end
however, i don't expect this will work because as far as i've seen the 'with' structure is not supported in php.`
nathan
05-Apr-2004 10:53
`On the post that says php4 automagically makes references, this appears to *not* apply to objects:
http://www.php.net/manual/en/language.references.whatdo.php
"Note: Not using the & operator causes a copy of the object to be made. If you use $this in the class it will operate on the current instance of the class. The assignment without & will copy the instance (i.e. the object) and $this will operate on the copy, which is not always what is desired. Usually you want to have a single instance to work with, due to performance and memory consumption issues."`
iryoku at terra dot es
30-Mar-2004 10:22
`You should have in mind that php4 keep assigned variables "automagically" referenced until they are overwritten. So the variable copy is not executed on assignment, but on modification. Say you have this:
$var1 = 5;
$var2 = $var1; // In this point these two variables share the same memory location
$var1 = 3; // Here $var1 and $var2 have they own memory locations with values 3 and 5 respectively
Don't use references in function parameters to speed up aplications, because this is automatically done. I think that this should be in the manual, because it can lead to confusion.
More about this here:
http://www.zend.com/zend/art/ref-count.php`
developer at sirspot dot com
03-Feb-2004 10:30
`Since references are more like hardlinks than pointers, it is not possible to change a reference to an object by using that same reference. For example:
The following WILL NOT WORK as expected and may even crash the PHP interpreter:
$object =& $object->getNext();
However, by changing the previous statement to use a temporary reference, this WILL WORK:
$temp =& $object;
$object =& $temp->getNext();`
add a note
Что делают ссылки Exceptions

Last updated: Fri, 26 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 10:36:09 2007 PST