$root = XCube_Root::getSingleton(); でよいのか

XOOPS Cube Legacy のお約束として

$root =& XCube_Root::getSingleton();

としてルートオブジェクトを取得する、というのがあります。ここで =& となっているのはPHP4サイトのために互換性を確保しているからであり、PHP5ではオブジェクトは = で参照(リファレンス)渡しになるので要らないんだよ、的な話をどこかで見かけました。調べてみるとこれはなかなかわかりづらい話で、いろいろな人がいろいろなサンプルを作って自分の理解を整理しています。わたしも学ばせていただいたお礼に、試行の結果をメモしておこうと思います。結論から言うとOK、のはず。

class Foo {
  public $member = 1;
}

$a =  new Foo;
$b =  $a;
$c =& $a;
var_dump($a, $b, $c); // ----- (1)

$a = new Foo;
var_dump($a, $b, $c); // ----- (2)

$a->member = 2;
var_dump($a, $b, $c); // ----- (3)

unset($a);
var_dump($a, $b, $c); // ----- (4)

(1)の結果はこんな感じでした。まったく見分けが付きません。

object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}

ところが、(2)新しく別のFooインスタンスを作成して$aを置き換えると……

object(Foo)#2 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#2 (1) {
  ["member"]=>
  int(1)
}

赤字の部分が違っています。これはオブジェクト毎に振られる固有のID(オブジェクトID)だそうで、オブジェクトが複製されているらしいことがわかります。

実際、(3)$aのメンバーの値を変えてみると……

object(Foo)#2 (1) {
  ["member"]=>
  int(2)
}
object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#2 (1) {
  ["member"]=>
  int(2)
}

$cが指しているオブジェクトの値も変わりました。ここまでの理解を図にしておきます。

オブジェクトのコピーと参照渡し

上が(1)の状態で、下が(2)の状態。○がインスタンス、□は……変数の値を格納しておく場所。PHP: オブジェクトと参照 - Manualには

オブジェクトが引数として渡されたり返り値となったり あるいは別の変数に代入されたりした場合、 それはエイリアスではありません。ID のコピーを保持し、 同じオブジェクトを指すようになるのです。

とあります。$bは、#1という「ID のコピーを保持し、 同じオブジェクトを指す」状態です。一方、PHP: リファレンスとは? - Manualには

リファレンスとは同じ変数の内容を異なった名前で コールすることを意味します。

とあります。$cは$aという「変数の内容を異なった名前でコール」しています。

というわけで、newやcloneなどで新しいインスタンスを作らないかぎり、= でも =& でも大丈夫そうです。getSingleton() の中を見るとそういう重複が起きないように工夫されている(だからSingletonというのでしょうね)ので、= でよさそうです。

念のため確認してみました。spl_object_hash()オブジェクトIDを調べられるようなので、次のような感じのコードを書きました。

<?php
include 'mainfile.php';
$root1 =& XCube_Root::getSingleton();
$root2 =  XCube_Root::getSingleton();
echo (spl_object_hash($root1) == spl_object_hash($root2)) ? 'Kept single.' : 'Duplicated!';

上の例では =&= の組み合わせです。これを様々に変えてみても、両者のオブジェクトIDは常に一致しました。

最後に、冒頭のテストコードに戻って、(4)$aを削除すると$cも削除されるのかと思いきや、

NULL
object(Foo)#1 (1) {
  ["member"]=>
  int(1)
}
object(Foo)#2 (1) {
  ["member"]=>
  int(2)
}

残っています。オブジェクトIDを指し示す変数が残っているかぎり、インスタンスは残っているみたいです。

 


友達に伝える
タグ: XOOPS PHP
作成: 2013/11/11 by:koji
更新: 2013/11/11 by:koji


カスタムモジュールのRSSフィードを出力する

Tech

d3forumに行かずにd3コメント統合する

新規ユーザー登録(無料)

  • メールニュース[週刊起-動線]の購読
  • コメントなどの投稿
  • ココロミの利用
  • 一部コンテンツの購読

ログイン

コメント

タグ(キーワード)