這個標題估計很多人會不屑一顧,變數賦值? excuse me?我們學開發的第一課就會了好不好。但是,就是這樣基礎的東西,反而會讓很多人蒙圈,比如,值和引用的關係。今天,我們就來具體講講。
首先,定義變數和賦值這個不用多說了吧
$a = 1; $b = '2'; $c = [4, 5, 6]; $d = new stdClass();
四個變量,分別定義了整數、字串、陣列的物件。這也是我們天天要處理的四種類型。
然後,變數給變數賦值。
$a1 = $a; $b1 = $b; $c1 = $c; $d1 = $d;
請注意,前三個的賦值都是正常的賦值,也就是具體內容的拷貝。當我們修改$a1的時候$a不會有變化。 $a1是新開的記憶體空間保存了我們的值。也就是說,他們的值是一樣的,但記憶體位址不一樣。是兩個沒啥關係的長得很像的人而已。
但是$d1和$d就不是了,這兩貨不只值是一樣的,記憶體位址也是一樣的。這種情況就是我們所說的引用賦值。當$d1發生變化時,$d2也會產生變化。
可以這麼說:引用賦值就是為原變數建立了一個Windows下的捷徑或是Linux中的軟連結。
用具體的例子來說明,首先是普通值的賦值:
// 普通赋值 $v = '1'; $c = $v; $c = '2'; echo $v, PHP_EOL; // '1' // 数组也是普通赋值 $arr1 = [1,2,3]; $arr2 = $arr1; $arr2[1] = 5; print_r($arr1); // [1, 2, 3]
$c不會對$v的值產生影響。 $arr2修改了下標1,也就是第二個數字為5,當然也不會對$arr1產生影響。
那麼物件形式的引用賦值呢?
// 对象都是引用赋值 class A { public $name = '我是A'; } $a = new A(); $b = $a; echo $a->name, PHP_EOL; // '我是A' echo $b->name, PHP_EOL; // '我是A' $b->name = '我是B'; echo $a->name, PHP_EOL; // '我是B'
果然不出所料,$b修改了name屬性的內容後,$a裡面的name也變成了$b所修改的內容。
在這種情況下,如果物件想要不是引用傳遞的,一是使用__clone(),也就是原型模式來進行自己的拷貝。二是從外面重新new一個唄。
// 使用克隆解决引用传递问题 class Child{ public $name = '我是A1的下级'; } class A1 { public $name = '我是A'; public $child; function __construct(){ $this->child = new Child(); } function __clone(){ $this->name = $this->name; // new 或者用Child的克隆都可以 // $this->child = new Child(); $this->child = clone $this->child; } } $a1 = new A1(); echo $a1->name, PHP_EOL; // 输出a1原始的内容 echo $a1->child->name, PHP_EOL; $b1 = $a1; echo $b1->name, PHP_EOL; // b1现在也是a1的内容 echo $b1->child->name, PHP_EOL; $b1->name = '我是B1'; // b1修改内容 $b1->child->name = '我是B1的下级'; echo $a1->name, PHP_EOL; // a1变成b1的内容了 echo $a1->child->name, PHP_EOL; // 使用__clone $b2 = clone $b1; // b2克隆b1 $b2->name = '我是B2'; // b2修改内容 $b2->child->name = '我是B2的下级'; echo $b1->name, PHP_EOL; // b1不会变成b2修改的内容 echo $b1->child->name, PHP_EOL; echo $b2->name, PHP_EOL; // b2修改的内容没问题,b1、b2不是一个货了 echo $b2->child->name, PHP_EOL;
物件的引用這一塊確實會容易讓人蒙圈。特別是更加複雜的對象,內部的屬性還有各種引用其他對象的時候。這種情況下一定要仔細確認引用賦值會不會帶來問題,如果有問題,就使用新物件或複製技術進行引用問題的處理。
最後,輕鬆一下,引用變數的賦值就跟我們給方法傳引用參數一樣的,使用一個&符號就可以啦!
// 引用赋值 $b = &$v; $b = '3'; echo $v, PHP_EOL;
今天我們更深入的學習和了解了一下PHP中的賦值問題,特別是普通賦值和引用賦值的問題。下回看程式碼和框架的時候可以注意注意別人是怎麼靈活使用這兩種賦值的哈,自己也能試試看能不能運用這兩種方式改造下自己曾經寫過的BUG哦!
测试代码: https://github.com/zhangyue0503/dev-blog/blob/master/php/201910/source/PHP%E7%9A%84%E5%8F%98%E9%87%8F%E8%B5%8B%E5%80%BC.php 参考文档: https://www.php.net/manual/zh/language.variables.basics.php
推薦學習:《PHP影片教學》