HOME>WEBプログラム覚書>PHP 参照渡し(リファレンス)と値渡し

PHP 参照渡し(リファレンス)と値渡し

プログラム(PHP4)ってものを勉強し始めてしばらくの間、 意味不明理解不能だったものが参照渡しでした。

function hoge(&$data){} こんなやつ。

なので今、PHP4を学んでる方は少ないと思いますが、 同じようにつまずいている方の何かの助けになるかもしれないので エントリーしときます。

間違ってたり、逆に混乱させたらごめんなさい・・・

絵を描いて考える。

広い草原があったので僕は家を作ろうとおもいました。

建築スキルはないけどネットで調べたら図面がありました。

PHP

  1. <?php
  2. class House
  3. {
  4.     private $wall = "";
  5.  
  6.     public function __construct($color)
  7.     {
  8.         $this->setWallColor($color);
  9.     }
  10.  
  11.     public function setWallColor($color)
  12.     {
  13.         $this->wall = $color;
  14.     }
  15.  
  16.     public function getWallColor()
  17.     {
  18.         return $this->wall;
  19.     }
  20. }
  21. ?>

壁の色を選ぶだけで家が建ちます。

PHP

  1. <?php
  2. $my_house = new House("White");
  3. ?>

白い壁が美しい家が建ちましたが残念ながら場所は選べませんでした。 勝手なところにできて住所も「A1」と決まってしまいました。

と、ここでOthersがやって来ました。

値渡し

other1はいいました。

「 ここはいい土地ですね。僕もここに家を建てようと思いますが 図面探すのも面倒だし、あなたと同じデザインの家でいいから さっさと建てたいんです。 」

僕はいいました。

「じゃあ僕の家をコピーしますか?」と。

PHP

  1. <?php
  2. // PHP5
  3. $other1_house = clone $my_house;
  4.  
  5. // PHP4
  6. //$other1_house = $my_house;
  7. ?>

白い壁の家が2棟できました。

PHP

  1. <?php
  2. echo "MyHouseの壁の色 : " . $my_house->getWallColor() . "<br />";
  3. echo "OtherHouseの壁の色 : " . $other1_house->getWallColor();
  4. ?>
MyHouseの壁の色 : White
OtherHouseの壁の色 : White

しばらくしてother1は言いました。やっぱ壁は赤がいいんじゃないかjk?

PHP

  1. <?php
  2. $other1_house->setWallColor("Red");
  3. ?>

こうして草原には白い壁と赤い壁の家が2棟建ちました。

PHP

  1. <?php
  2. echo "MyHouseの壁の色 : " . $my_house->getWallColor() . "<br />";
  3. echo "OtherHouseの壁の色 : " . $other1_house->getWallColor();
  4. ?>
MyHouseの壁の色 : White
OtherHouseの壁の色 : Red


参照渡し

other2は言いました。「おっ!いい家あるじゃん。俺もここ住むわ。」と。

PHP

  1. <?php
  2. // PHP5
  3. $other2_house = $my_house;
  4.  
  5. // PHP4
  6. //$other2_house =& $my_house;
  7. ?>

こうしてother2は強引に僕の家に住みはじめました。

PHP

  1. <?php
  2. echo "MyHouseの壁の色 : " . $my_house->getWallColor() . "<br />";
  3. echo "Other2Houseの壁の色 : " . $other2_house->getWallColor();
  4. ?>
MyHouseの壁の色 : White
Other2Houseの壁の色 : White

ある時、other2は言いました。「やっぱ壁は赤だろjk」と。

PHP

  1. <?php
  2. $other2_house->setWallColor("Red");
  3. ?>

今は「other2の家 = 僕の家」です。 other2が壁の色を変更するってことは 僕の家の壁が変更されるってことです。

PHP

  1. <?php
  2. echo "MyHouseの壁の色 : " . $my_house->getWallColor() . "<br />";
  3. echo "Other2Houseの壁の色 : " . $other2_house->getWallColor();
  4. ?>
MyHouseの壁の色 : Red
Other2Houseの壁の色 : Red

こうして草原には赤い壁の家が1棟建ちました。

解説

うまく説明できてないかもですが、一応これが参照渡しと値渡しの違いです。

現実のプログラムに当てはめてみると 土地がメモリ、家がオブジェクト、住所がオブジェクトのメモリアドレス(※1)となります。 値渡しはメモリに新たにオブジェクトを格納しますが、 参照渡しは「メモリアドレスを教える」 ことになります。

※1

変数宣言したりオブジェクトを作ったりすると メモリに格納されます。その格納された場所を表すのが メモリアドレスとなります。

PHPではメモリのどこに格納するのかを指定することはたぶんできませんので 家を建てたけど場所を選べなかったと書いてますが、他の言語では 指定できたりしなきゃいけなかったりするっぽいです。



なぜ参照渡しなのか

様々な理由があるかと思いますが、僕が知ってる範囲では、 そのほうが便利だからwってこととメモリを節約できるってことです。

メモリの節約に関しては上記の例では普通の一軒家ですが 花輪君みたいな豪邸を建てた場合を考えるとなんとなくわかるかと思います。 土地は有限ですから豪邸がどんどん建つと土地(メモリ)の空きがどんどんなくなってしまいます。

なので、数値や文字列に比べ大きな家になりがちな オブジェクトや配列などは多くのプログラム言語では 参照渡しが基本となっているようです。(PHP4は値渡しがデフォ)

どんな時に参照渡しを使うのか

PHP4を利用していて参照渡しを知ったとき まったくもって使いどころがわかりませんでした。 オブジェクトを利用するようになって便利さがわかってきた気がします。

異なるスコープで加えた変更が元のところでも変更されるので いちいちreturnしなくてよいためオブジェクトの受け渡しが楽。

んーうまく伝えられなくてすみません・・・。

サンプルコード

例えば下記のようなコードがあったとして

PHP

  1. <?php
  2. class Human
  3. {
  4.     private $first_name = "";
  5.     private $last_name = "";
  6.  
  7.     public function __construct($last_name, $first_name)
  8.     {
  9.         $this->setFirstName($first_name);
  10.         $this->setLastName($last_name);
  11.     }
  12.  
  13.     public function getName()
  14.     {
  15.         return $this->getLastName() . " " . $this->getFirstName();
  16.     }
  17.  
  18.     public function getFirstName()
  19.     {
  20.         return $this->first_name;
  21.     }
  22.  
  23.     public function getLastName()
  24.     {
  25.         return $this->last_name;
  26.     }
  27.  
  28.     public function setLastName($last_name)
  29.     {
  30.         $this->last_name = $last_name;
  31.     }
  32.  
  33.     private function setFirstName($first_name)
  34.     {
  35.         $this->first_name = $first_name;
  36.     }
  37. }
  38.  
  39. class Couple
  40. {
  41.     private $man;
  42.     private $woman;
  43.  
  44.     public function __construct(Human $man, Human $woman)
  45.     {
  46.         $this->man = $man;
  47.         $this->woman = $woman;
  48.     }
  49.  
  50.     public function marriage()
  51.     {
  52.         $this->woman->setLastName($this->man->getLastName());
  53.     }
  54. }
  55. ?>

参照渡しで実行すると

PHP

  1. <?php
  2. // 2人の男女がいました。
  3. $honeo = new Human("馬野", "骨雄");
  4. $kadoko = new Human("机野", "角子");
  5.  
  6. // 二人は付き合いはじめました。
  7. $love_group1 = new Couple($honeo, $kadoko);
  8.  
  9. // 勢いあまって結婚しますた。
  10. $love_group1->marriage();
  11.  
  12. // 苗字が変わりました。
  13. echo $honeo->getName() . "<br />";
  14. echo $kadoko->getName();
  15. ?>
馬野 骨雄
馬野 角子

こうなりますが、値渡しだと

PHP

  1. <?php
  2. // 2人の男女がいました。
  3. $honeo2 = new Human("馬野", "骨雄");
  4. $kadoko2 = new Human("机野", "角子");
  5.  
  6. // 二人は付き合いはじめました。
  7. $love_group2 = new Couple(clone $honeo2, clone $kadoko2);
  8.  
  9. // 勢いあまって結婚しますた。
  10. $love_group2->marriage();
  11.  
  12. // 苗字がかわりません。
  13. echo $honeo2->getName() . "<br />";
  14. echo $kadoko2->getName();
  15. ?>
馬野 骨雄
机野 角子

当然こうなります。

もし値渡しで苗字が変わるようにするには Coupleクラスでprivateだったメンバをpublicにしたり、 アクセス権限変えるのはだいぶ問題あるのでメソッド追加とかに なると思います。

PHP

  1. <?php
  2. class Couple2
  3. {
  4.     public $man;
  5.     public $woman;
  6.  
  7.     public function __construct(Human $man, Human $waman)
  8.     {
  9.         $this->man = $man;
  10.         $this->woman = $waman;
  11.     }
  12.  
  13.     public function marriage()
  14.     {
  15.         $this->woman->setLastName($this->man->getLastName());
  16.     }
  17. }
  18. ?>

ここでは簡単にアクセス権限を変えてます。上記を利用したコードが下記です。

PHP

  1. <?php
  2. // 2人の男女がいました。
  3. $honeo3 = new Human("馬野", "骨雄");
  4. $kadoko3 = new Human("机野", "角子");
  5.  
  6. // 二人は付き合いはじめました。
  7. $love_group3 = new Couple2(clone $honeo3, clone $kadoko3);
  8.  
  9. // 勢いあまって結婚しますた。
  10. $love_group3->marriage();
  11.  
  12. // 苗字が変わりました。
  13. echo $love_group3->man->getName() . "<br />";
  14. echo $love_group3->woman->getName();
  15. ?>
馬野 骨雄
馬野 角子

どうでしょう?参照渡しじゃないと不便な気がしませんか?

あ・・・記憶が蘇ってまいりました。 そういえばクラス使い始めたころアロー演算子使いまくりのコード書いてましたわ。

PHP4でアロー演算子使いまくりの方は参照渡しを利用してみると すっきりする可能性大ですので是非試してみてください。

PHP5の変数について

PHP5ではPHP4と違いオブジェクトの受け渡しはデフォで参照渡しとなる。って 思い込んでましたが実はそれは間違いのようです。

参照のように振舞うが実は違うという、PHP5の変数の話。

投稿日 2009年1月21日 20:11
カテゴリ ETC | PHP
タグ 言語仕様
トラックバック URL http://www.kantenna.com/cgi-bin/mt504/mt-tb.cgi/1149

コメント

コメントする
Name
Email Address
URL