KANTENNA.COM

Solarized

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の変数の話。

プログラミングPHP 第2版
作者:Peter MacIntyre | 価格:¥ 3,990

トラックバック(0)

コメント

コメントする
Name
Email Address
URL
TIME LINE
2012
01.26

[jQuery Mobile]ダイアログ

jQuery Mobileにおけるダイアログの扱いはウインドウではなくページ。 なので通常のページと同様に扱える。ダイアログウインドウを出す。じゃなくダイアログページに遷移する。的な。

2012
01.25

[Ubuntu11.10]Ubuntuのインストール後の設定

インストール完了後の環境構築。PC起動時いちいちBIOSからブートドライブ選んで ブートするのかと思ってたら起動時にOS選択画面が出てくる。

すばらしいですね。

2012
01.24
2012
01.23

MinGW+Mintty+Git

MinGW+Mintty+Gitをやろうとして失敗に終わった。このエントリーには収穫できるものはありません。

2012
01.21

[PHP]共有サーバーユーザーのためのPEARインストール方法

共有サーバーでは自由にPEARのパッケージがインストールできないので、 プロジェクトローカルに設置することになりますが、以前httpベースのものを使ってみたんですけど、 やたら重くて使い物にならなかったので、僕は普通にFTPでアップするようにしてます。

ってことでプロジェクトローカルへのPEARのインストール方法。

2012
01.14

[WordPress]3.0から非推奨になったこと。

いろいろ調べてテーマ作ってたんだけど 3.0からheader.phpとfooter.phpがないテーマは非推奨になっとった。

2012
01.12

[WordPress] 次の投稿と前の投稿を取得する。

次の投稿とか前の投稿を取得するget_adjacent_post()が、どうもループ内じゃないと利用できないようになっている模様。

2012
01.08

[WordPress]囲み型ショートコードの改行とかエスケープとか。

囲み型ショートコードのコンテンツを普通に受け取ると、改行があったりセミコロンとかがエスケープされた状態になっている。 JavascriptとかPHPを書く場合、まじうっとおしいので何とかしてみる。