[PHP-users 10606] Re: 1つのインスタンスを参照する2つの変数のチェック方法

KUROSAWA Akira php-users@php.gr.jp
Mon, 07 Oct 2002 21:30:45 +0900


黒澤です。

WADA Masashi wrote:
>>>上記の check_reference() を利用した次のコードを実行してみると、
>>>
>>>$a = 1;
>>>$b = $a;
>>>print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");
>>>$a = 2;
>>>print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");
>>>
>>>結果は
>>>
>>>1, 1 : ref.
>>>2, 1 : not ref.
>>>
>>>となります(テスト環境はPHP4.1.2/4.2.2)。
>>
>>多分、タイプミスだと思うんですが、2行目の「$b = $a」は「$b =& $a」ですよね。
>>だとすれば、これは期待通りの動作です。
> 
> 
> いえ、「$b = $a」です。

大変失礼致しました。
和田さんがせっかく書いてくれたコードを検証もせず、コードを見ただけで
回答してしまいました。スイマセン。m(_ _)m

実際に動かしてみましたが、この結果にはちょっと驚きました。
(後半の検証結果をご参照ください)

>  メモリの有効利用と高速化を目指して、PHP4から Reference Counting
> が導入されています。例えば次のようなコードについて考えてみます。
> 
>   $a = 1;  //---(1)
>   $b = $a; //---(2)
>   $a = 2;  //---(3)
>   $b = 3;  //---(4)
> 
>  (1).$a はメモリ上に確保された 1 という値を参照します。
>  (2)."="は代入演算子ですから、本来なら $b に 1 という値がコピー
>    されるはずです。しかしPHPの内部では $b は(1)で確保された 1
>    を参照するだけに留めています。
>  (3).新たな値 2 がメモリ上に用意されて、$a はこちらを参照します。
>    $b は(1)で確保された 1 を参照したままです。
>   (4).新たな値 3 がメモリ上に用意されて、$b はこちらを参照します。
>    (1)で確保された 1 は誰も参照しなくなったのでメモリが解放さ
>    れます。
> 
> というのが Reference Counting の考え方です。私の理解が間違ってい
> るかもしれないので、Zend のページで確認してみて下さい。
>http://www.zend.com/zend/art/ref-count.php
> 
>  プログラマーが「$b = & $a;」で直接指示するような Reference と
> は少し意味が違うので注意しましょう。

ご丁寧な説明、ありがとうございます。
Zendのページは解読に少し時間がかかりそうなので、後でゆっくり
読ませて頂きます。

> 
(省略)
> 
> それにしても
> 
> $a = 1;
> $b = 1;
> print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");
> $a = 2;
> print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");
> 
> の結果が
> 
> 1, 1 : ref.
> 2, 1 : not ref.
> 
> になるのはおもしろいですね。

何故こうなるのか検証してみました。
どうやら check_reference() のバグのようですね(^^;

check_referernce()関数内の2つのif文
if($var1 . "." == $var2)
if($var2 == $var1)
の比較演算子 "==" を "==="(イコール3つ)に変更すると期待通りの動きになる
ようです。

『文字列の変換』
http://www.php.net/manual/ja/language.types.string.php#language.types.string.conversion
 数値として文字列が評価された時。。。 文字列の最初の部分により値が決まり
ます。

と書かれているので、$var1の後ろに付加されているはずのドットが無視されて
しまっている
ために例にあげて頂いたような動きになるようです。

で、修正後のソースで最初のソースを実行してみました。

$a = 1;
$b = $a;
print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");
$a = 2;
print "$a, $b : ".(check_reference($a, $b) ? "ref.\n" : "not ref.\n");

結果は

1, 1 : not ref.
2, 1 : not ref

となりました。(^^;

んー、Reference Counting がプログラミング上どのように影響するのか
よくわからなくなってきました。(^^;

ご提示頂いたZendページを解読してまとめたいと思います。
(少々時間がかかると思いますが。。。)
ありがとうございました。

-- 
株式会社システムジェイ
    システム開発グループ
    黒澤 明  kurosawa@systemj.com