オブジェクトの代入

まず、オブジェクトとはオブジェクト型の変数で、文字列型の変数には文字列が格納されているように、オブジェクト型の変数にはオブジェクト(クラスのインスタンス)が格納されています。

次に、変数に変数を代入するという事は、右辺の変数の値を左辺の変数にコピーするという事で、変数にオブジェクトを代入するという事は、右辺のオブジェクトを左辺の変数にコピーするという事であり、代入の結果、左辺の変数は右辺の変数と全く同じオブジェクト(クローン)になります。

これはPHP4の場合で、PHP5では違った結果になります。

PHP4でのオブジェクトの代入

PHP4で、変数にオブジェクトを代入しようとする場合、他の型の変数の場合と同様、単にコピーを代入するかリファレンスを代入するかの2通りありました。以下のサンプルと結果をご覧下さい。

<pre>
<?php
    class HUMAN{
        var $name;
        function HUMAN($name){
            $this->name = $name;
        }
        function greeting(){
            echo "I'm {$this->name}.\n";
        }
        function change_my_name($name){
            $this->name = $name;
        }
    }
    
    #オブジェクトを生成
    $hodenasu = new HUMAN("Hodenasu");
    
    #オブジェクトのコピーを代入
    $clone_hodenasu = $hodenasu;
    
    #オブジェクトへのリファレンスを代入
    $ref_hodenasu =& $hodenasu;

    $hodenasu->greeting();
    $clone_hodenasu->greeting();
    $ref_hodenasu->greeting();
    
    $ref_hodenasu->change_my_name("Reference");
    $clone_hodenasu->change_my_name("Clone");
    
    echo "\n";
    
    $hodenasu->greeting();
    $clone_hodenasu->greeting();
    $ref_hodenasu->greeting();
?>
</pre>
I'm Hodenasu.
I'm Hodenasu.
I'm Hodenasu.

I'm Reference.
I'm Clone.
I'm Reference.

「変数$hodenasu」に生成したオブジェクトを格納、「変数$clone_hodenasu」にそのコピー(クローン)を代入し、「変数$ref_hodenasu」にはリファレンスを代入しました。 サンプルの結果は予想した通りだと思います。

PHP5でのオブジェクトの代入

一方、PHP5では、変数にオブジェクトを代入しようとする場合、単にコピーを代入するかリファレンスを代入するか、割り当てるかの3通りあります。

“割り当てる”という言葉の意味が解かりづらいと思いますが、これは“代理人を生成する”という意味で解釈して下さい(もっと解かりづらいか・・・)。まぁ、以下のサンプルと結果をご覧下さい。

<pre>
<?php
    class HUMAN{
        var $name;
        function HUMAN($name){
            $this->name = $name;
        }
        function greeting(){
            echo "I'm {$this->name}.\n";
        }
        function change_my_name($name){
            $this->name = $name;
        }
    }
    #オブジェクトを生成
    $hodenasu = new HUMAN("Hodenasu");

    #オブジェクトへのリファレンスを代入
    $ref_hodenasu =& $hodenasu;

    #オブジェクトを割り当てる(代理人の様なもの?を代入)
    $agent_hodenasu = $hodenasu;

    #オブジェクトのクローン(コピー)を代入
    $clone_hodenasu = clone $hodenasu;

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$ref_hodenasu->change_my_name("Reference");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$agent_hodenasu->change_my_name("Agent");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$agent_hodenasu = new HUMAN("new_Agent");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$ref_hodenasu = new HUMAN("new_Reference");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$ref_hodenasu = clone new HUMAN("new_clone_Reference");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();

    $str = '$ref_hodenasu =& new HUMAN("new_ref_Reference");';
    eval($str);
    echo "\n&gt; ", $str, "\n\n";

    $hodenasu->greeting();
    $ref_hodenasu->greeting();
    $agent_hodenasu->greeting();
    $clone_hodenasu->greeting();
?>
</pre>
I'm Hodenasu.
I'm Hodenasu.
I'm Hodenasu.
I'm Hodenasu.

> $ref_hodenasu->change_my_name("Reference");

I'm Reference.
I'm Reference.
I'm Reference.
I'm Hodenasu.

> $agent_hodenasu->change_my_name("Agent");

I'm Agent.
I'm Agent.
I'm Agent.
I'm Hodenasu.

> $agent_hodenasu = new HUMAN("new_Agent");

I'm Agent.
I'm Agent.
I'm new_Agent.
I'm Hodenasu.

> $ref_hodenasu = new HUMAN("new_Reference");

I'm new_Reference.
I'm new_Reference.
I'm new_Agent.
I'm Hodenasu.

> $ref_hodenasu = clone new HUMAN("new_clone_Reference");

I'm new_clone_Reference.
I'm new_clone_Reference.
I'm new_Agent.
I'm Hodenasu.

> $ref_hodenasu =& new HUMAN("new_ref_Reference");

I'm new_clone_Reference.
I'm new_ref_Reference.
I'm new_Agent.
I'm Hodenasu.

ちょっとゴチャゴチャしてしまいました。最初の方の結果を見る限りでは、「変数$ref_hodenasu」と「変数$agent_hodenasu」は同じ様にも見えますが、新しくオブジェクトを生成して代入した場合の結果が異なります。「変数$ref_hodenasu」は良いとして、「変数$agent_hodenasu」は新しいオブジェクトを代入された瞬間、「変数$hodenasu」との代理人契約が切れてしまいました。

変な表現をしてしまいましたが、「$agent_hodenasu = $hodenasu;」の結果、「変数$agent_hodenasu」が、PHP4では代入元のオブジェクトのクローン(コピー)になっていたのに、PHP5ではリファレンスの様な、でも違う代理人の様なものになったなぁという事を理解できたと思います。

でも実際はリファレンスです(え?)。「変数$agent_hodenasu」は「変数$hodenasu」のリファレンスですが、完全なリファレンスではないのです。どういう事かというと、“純粋なリファレンスではない”という事(へ?)。つまり、「変数$ref_hodenasu」は「変数$hodenasu」と共通のリファレンスを持ち、同じオブジェクトを指すようにセットされた変数ですが、「変数$agent_hodenasu」の方は、「変数$hodenasu」と共通のリファレンスを持っているというわけではなく(実際はどうか分かりませんが)、同じオブジェクトとして振る舞うように“割り当て”られた変数なので、「変数$hodenasu」か「変数$agent_hodenasu」のどちらかに別のオブジェクトかその他の型の値を代入しても、両方の変数の中身が変わるということはありません。

で、クローン(コピー)を代入するためには、「$clone_hodenasu = clone $hodenasu;」と、代入演算子「=(イコール)」の後に「clone」を付けてやる必要があります。

new」と「clone()

クラスのインスタンスつまりオブジェクトを生成する時は「new」を使いました。そしてオブジェクトのクローン(コピー)を代入する時には「clone」を使いました。「new」は新しくオブジェクトを生成する演算子、「clone」はオブジェクトのクローンを生成する命令(「echo」の様な、関数の様でいて関数ではない言語構造)です。以下にサンプルと結果のみ。

<pre>
<?php
    class HODE{
        //empty
    }
    
    #オブジェクトの生成
    var_dump( new HODE );
    
    #オブジェクトのクローンの生成
    $hode = new HODE;
    var_dump( clone $hode );
?>
</pre>
object(HODE)#1 (0) {
}
object(HODE)#2 (0) {
}
作成日:2004年12月16日 最終更新日:2004年12月16日
【通常モード で表示】