|
|
Многие синтаксические конструкции PHP реализованы через механизм ссылок, поэтому всё сказанное выше о ссылочном связывании применимо также и к этим конструкциям. Некоторые конструкции, вроде передающих и возвращающих по ссылке, рассмотрены ранее. Другие конструкции, использующие ссылки:
Если вы объявляете переменную как global $var, вы фактически создаёте ссылку на глобальную переменную. Это означает то же самое, что:
Это значит, например, что сброс (unset) $var не приведёт к сбросу глобальной переменной.
В методах объекта, $this всегда является ссылкой на вызывающий объект.
add a note
User Contributed Notes
Неявное использование механизма ссылок
Mildred
25-May-2007 12:20
Someone said that BenBe's function is_ref() was broken for testing objects. I didn't test it but I rewrote it and I know it works for objects. Here is the new version :
<?php
function is_ref(&$a, &$b){
if(gettype($a) !== gettype($b)) return false;
$same = false;
if(is_array($a)){
$key = uniqid("is_ref_", true);
while(isset($a[$key]))$key = uniqid("is_ref_", true);
if(isset($b[$key])) return false;
$data = uniqid("is_ref_data_", true);
$a[$key] =& $data;
$same = ((isset($b[$key])) and ($b[$key] === $data));
unset($a[$key]);
}elseif(is_object($a)){
if(get_class($a) !== get_class($b)) return false;
$key = uniqid("is_ref_", true);
while(isset($a->$key))$key = uniqid("is_ref_", true);
if(isset($b->$key)) return false;
$data = uniqid("is_ref_data_", true);
$a->$key =& $data;
$same = ((isset($b->$key)) and ($b->$key === $data));
unset($a->$key);
}elseif(is_resource($a)){
if(get_resource_type($a) !== get_resource_type($b))return false;
$same = ((string) $var1) === ((string) $var2);
}else{
if($a !== $b) return false;
$data = uniqid("is_ref_", true);
while($data === $a) $data = uniqid("is_ref_", true);
$save = $a; $a = $data; $same = ($a === $b); $a = $save; }
return $same;
}
?>
Steve Clay
06-Apr-2007 06:24
BenBE's function is broken for testing objects. Here's a variation on it just for testing objects:
<?php
function same_obj(&$var1, &$var2) {
if ($var1 !== $var2) {
return false;
}
$same = false;
$key = uniqid("same_obj_", true);
$var1->$key = $key;
if (isset($var2->$key) && $var2->$key == $key) {
$same = true;
}
unset($var1->$key);
return $same;
}
$f1 =& new Foo;
$f2 = array(&$f1);
$f3 = $f2;
echo (int)same_obj($f1, $f3[0]); ?>
BenBE at omorphia dot de
07-Jan-2007 11:37
Hi,
If you want to check if two variables are referencing each other (i.e. point to the same memory) you can use a function like this:
<?php
function same_type(&$var1, &$var2){
return gettype($var1) === gettype($var2);
}
function is_ref(&$var1, &$var2) {
if(!same_type($var1, $var2)) {
return false;
}
$same = false;
if(is_array($var1)) {
do {
$key = uniqid("is_ref_", true);
} while(array_key_exists($key, $var1));
if(array_key_exists($key, $var2)) {
return false;
}
$data = uniqid("is_ref_data_", true);
$var1[$key] =& $data;
if(array_key_exists($key, $var2)) {
if($var2[$key] === $data) {
$same = true;
}
}
unset($var1[$key]);
} elseif(is_object($var1)) {
if(get_class($var1) !== get_class($var2)) {
return false;
}
$obj1 = array_keys(get_object_vars($var1));
$obj2 = array_keys(get_object_vars($var2));
do {
$key = uniqid("is_ref_", true);
} while(in_array($key, $obj1));
if(in_array($key, $obj2)) {
return false;
}
$data = uniqid("is_ref_data_", true);
$var1->$key =& $data;
if(isset($var2->$key)) {
if($var2[$key] === $data) {
$same = true;
}
}
unset($var1->$key);
} elseif (is_resource($var1)) {
if(get_resource_type($var1) !== get_resource_type($var2)) {
return false;
}
return ((string) $var1) === ((string) $var2);
} else {
if($var1!==$var2) {
return false;
}
do {
$key = uniqid("is_ref_", true);
} while($key === $var1);
$tmp = $var1; $var1 = $key; $same = $var1 === $var2; $var1 = $tmp; }
return $same;
}
?>
Although this implementation is quite complete, it can't handle function references and some other minor stuff ATM.
This function is especially useful if you want to serialize a recursive array by hand.
The usage is something like:
<?php
$a = 5;
$b = 5;
var_dump(is_ref($a, $b)); $a = 5;
$b = $a;
var_dump(is_ref($a, $b)); $a = 5;
$b =& $a;
var_dump(is_ref($a, $b)); echo "---\n";
$a = array();
var_dump(is_ref($a, $a)); $a[] =& $a;
var_dump(is_ref($a, $a[0])); echo "---\n";
$b = array(array());
var_dump(is_ref($b, $b)); var_dump(is_ref($b, $b[0])); echo "---\n";
$b = array();
$b[] = $b;
var_dump(is_ref($b, $b)); var_dump(is_ref($b, $b[0])); var_dump(is_ref($b[0], $b[0][0])); echo "---\n";
var_dump($a);
var_dump($b);
?>
* Please note the internal behaviour of PHP that seems to do the reference assignment BEFORE actually copying the variable!!! Thus you get an array containing a (different) recursive array for the last testcase, instead of an array containing an empty array as you could expect.
BenBE.
ludvig dot ericson at gmail dot com
27-Feb-2006 03:36
For the sake of clarity:
$this is a PSEUDO VARIABLE - thus not a real variable. ZE treats is in other ways then normal variables, and that means that some advanced variable-things won't work on it (for obvious reasons):
<?php
class Test {
var $monkeys = 0;
function doFoobar() {
$var = "this";
$$var->monkeys++; }
}
$obj = new Test;
$obj->doFoobar(); var_dump($obj->monkeys); ?>
ksamvel at gmail dot com
10-Feb-2006 09:02
One may check reference to any object by simple operator==( object). Example:
class A {}
$oA1 = new A();
$roA = & $oA1;
echo "roA and oA1 are " . ( $roA == $oA1 ? "same" : "not same") . "<br>";
$oA2 = new A();
$roA = & $roA2;
echo "roA and oA1 are " . ( $roA == $oA1 ? "same" : "not same") . "<br>";
Output:
roA and oA1 are same
roA and oA1 are not same
Current technique might be useful for caching in objects when inheritance is used and only base part of extended class should be copied (analog of C++: oB = oA):
class A {
/* Any function changing state of A should set $bChanged to true */
public function isChanged() { return $this->bChanged; }
private $bChanged;
//...
}
class B extends A {
// ...
public function set( &$roObj) {
if( $roObj instanceof A) {
if( $this->roAObj == $roObj &&
$roObj->isChanged()) {
/* Object was not changed do not need to copy A part of B */
} else {
/* Copy A part of B */
$this->roAObj = &$roObj;
}
}
}
private $roAObj;
}
Sergio Santana: ssantana at tlaloc dot imta dot mx
16-Dec-2005 08:41
*** WARNING about OBJECTS TRICKY REFERENCES ***
-----------------------------------------------
The use of references in the context of classes
and objects, though well defined in the documentation,
is somehow tricky, so one must be very careful when
using objects. Let's examine the following two
examples:
<?php
class y {
public $d;
}
$A = new y;
$A->d = 18;
echo "Object \$A before operation:\n";
var_dump($A);
$B = $A; $C =& $A; $B->d = 1234;
echo "\nObject \$B after operation:\n";
var_dump($B);
echo "\nObject \$A implicitly modified after operation:\n";
var_dump($A);
echo "\nObject \$C implicitly modified after operation:\n";
var_dump($C);
$A = new y;
$A->d = 25200;
echo "\nObject \$B after \$A modification:\n";
var_dump($B); echo "\nObject \$A after \$A modification:\n";
var_dump($A);
echo "\nObject \$C implicitly modified after \$A modification:\n";
var_dump($C); ?>
Thus, note the difference between assignments $X = $Y and $X =& $Y.
When $Y is anything but an object instance, the first assignment means
that $X will hold an independent copy of $Y, and the second, means that
$X and $Y will refer to the same thing, so they are tight together until
either $X or $Y is forced to refer to another thing. However, when $Y
happens to be an object instance, the semantic of $X = $Y changes and
becomes only slightly different to that of $X =& $Y, since in both
cases $X and $Y become references to the same object. See what this
example outputs:
Object $A before operation:
object(y)#1 (1) {
["d"]=>
int(18)
}
Object $B after operation:
object(y)#1 (1) {
["d"]=>
int(1234)
}
Object $A implicitly modified after operation:
object(y)#1 (1) {
["d"]=>
int(1234)
}
Object $C implicitly modified after operation:
object(y)#1 (1) {
["d"]=>
int(1234)
}
Object $B after $A modification:
object(y)#1 (1) {
["d"]=>
int(1234)
}
Object $A after $A modification:
object(y)#2 (1) {
["d"]=>
int(25200)
}
Object $C implicitly modified after $A modification:
object(y)#2 (1) {
["d"]=>
int(25200)
}
Let's review a SECOND EXAMPLE:
<?php
class yy {
public $d;
function yy($x) {
$this->d = $x;
}
}
function modify($v)
{
$v->d = 1225;
}
$A = new yy(3);
var_dump($A);
modify($A);
var_dump($A);
?>
Although, in general, a formal argument declared
as $v in the function 'modify' shown above, implies
that the actual argument $A, passed when calling
the function, is not modified, this is not the
case when $A is an object instance. See what the
example code outputs when executed:
object(yy)#3 (1) {
["d"]=>
int(3)
}
object(yy)#3 (1) {
["d"]=>
int(1225)
}
Sergio Santana: ssantana at tlaloc dot imta dot mx
10-Aug-2005 09:30
Sometimes an object's method returning a reference to itself is required. Here is a way to code it:
<?php
class MyClass {
public $datum;
public $other;
function &MyRef($d) { $this->datum = $d;
return $this; }
}
$a = new MyClass;
$b = $a->MyRef(25); echo "This is object \$a: \n";
print_r($a);
echo "This is object \$b: \n";
print_r($b);
$b->other = 50;
echo "This is object \$a, modified" .
" indirectly by modifying ref \$b: \n";
print_r($a);
?>
This code outputs:
This is object $a:
MyClass Object
(
[datum] => 25
[other] =>
)
This is object $b:
MyClass Object
(
[datum] => 25
[other] =>
)
This is object $a, modified indirectly by modifying ref $b:
MyClass Object
(
[datum] => 25
[other] => 50
)
|