特集・コラム

メニュー

PHPer上級者になるために知っておきたいこと

vol.42 ‐ PHP『関数仕様編 その7(参照について その4)』

投稿日時:2014/06/12 02:06

カテゴリ: PHPer上級者になるために知っておきたいこと

参照のお題ですでに四回目でございます…あと少しだけおつきあいいただければ幸いです。

さて早速ですが。
スカラー値以上に、配列の参照は色々と面倒だったり厄介だったり困難だったり至難だったりいたします。
用途にもよりますが、arrayObjectのご利用を早々に視野に入れていただくと、大変に「楽」かと存じます。

まず。
配列のcopyについて、考えてみましょう。
簡単なコードで、まず「配列の代入式は、配列のcopyになる」事を、改めて押さえておきましょう。

$awk = array(1,2,3);
$awk2 = $awk;
$awk[] = ‘awk';
$awk2[] = ‘awk2′;
var_dump($awk);
var_dump($awk2);

また。
配列も当然ですがcopy on writeですので、代入式のタイミングではメモリをさほど食いません。
片方に「変化を与えた」タイミングで一気にメモリに襲いかかります…ってあたりは、
以下のサンプルコードでご確認ください。

var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));
echo “\n”;
//
$awk = array();
for($i = 0; $i < 10000; $i ++) {
$awk[] = 'a';
}
var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));
echo "\n";
//
$awk2 = $awk;
//
var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));
echo "\n";
//
$awk2[] = 'b';
//
var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));

こちらで、「$awk = array();」を「$awk = new arrayObject();」に変えると、
(当然ではありますが)メモリは食われません。
用途にもよりますが、もし用途的に「arrayObjerctで問題が無く」かつ「メモリがちょっと(以上)心配である」場合、
一考してみるのもよろしいのではないかと思います。

さて…このarrayObjectの挙動ですが。理解するには「配列型(array)と、
インスタンス(オブジェクト型(arrayObject))の違い」を把握する必要があります。
ですので、少し寄り道をして「インスタンス(オブジェクト型)」の参照周りについて、理解をしておきましょう。
まずは簡単に、このコードから。

class hoge {
}
//
$a = new hoge();
$b = &$a;
//
$a->a_ = 10;
$b->b_ = 20;
//
var_dump($a);
var_dump($b);

こちらにおいて結果が

object(hoge)#1 (2) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
}
object(hoge)#1 (2) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
}

となるのはまぁ、何となく今までの流れからも「分かる」状態かと思います。
お次はこちら。

class hoge {
}
//
$a = new hoge();
$c = $a;
//
$a->a_ = 10;
$c->c_ = 30;
var_dump($a);
var_dump($c);

$aと$cは、値を入れた瞬間に「copy on writeがあるから、別の物に分岐する」…では、ありません。

object(hoge)#1 (2) {
[“a_”]=>
int(10)
[“c_”]=>
int(30)
}
object(hoge)#1 (2) {
[“a_”]=>
int(10)
[“c_”]=>
int(30)
}

先ほどと同じような結果になるわけですね。
なぜでしょうか?
少し前で使ってました、PHPの内部構造で変数を管理している
「変数名を管理するテーブル」「実際の値を管理するテーブル」で、状況を見てみましょう。

変数名を管理するテーブル

変数名

値が入っている所の行数

a

1行目

c

2行目

実際の値を管理するテーブル

行数

変数の型

is_ref

1行目

クラスインスタンス(オブジェクト)

オブジェクトID #1

true

このようになっているからです。
もう少し、別のコードも見てみましょう。

class hoge {
}
//
$a = new hoge();
$b = &$a;
$c = $a;
//
$a->a_ = 10;
$b->b_ = 20;
$c->c_ = 30;
var_dump($a);
var_dump($b);
var_dump($c);
echo “——\n”;
//
$a = new hoge();
var_dump($a);
var_dump($b);
var_dump($c);

結果は以下のようになります。

object(hoge)#1 (3) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
[“c_”]=>
int(30)
}
object(hoge)#1 (3) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
[“c_”]=>
int(30)
}
object(hoge)#1 (3) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
[“c_”]=>
int(30)
}
——
object(hoge)#2 (0) {
}
object(hoge)#2 (0) {
}
object(hoge)#1 (3) {
[“a_”]=>
int(10)
[“b_”]=>
int(20)
[“c_”]=>
int(30)
}

このようになります。
よく「PHP5以降、newはクラスインスタンスの参照を返すようになった」と言われていますが、
厳密には、ちょっと違います。
newは「オブジェクトIDを値とした変数を返す」となります。
通常の代入式だと「オブジェクトID、のcopy」を作るので、
結果的に「(値が入っている場所が違っても)同じオブジェクトIDだから同じモノを指している」状況になります。

上述のサンプルコードをよく確認して
・「$b = &$a;」があるので、$aと$bは「is_refがtrueとなり、片方の変数の値を変えるともう片方も変わる」
・「$c = $a;」があるので、$aと$bは「is_refがfalseとなり、片方の変数の値を変えてももう片方は変わらない」
ことと、それとは別に
・$a、$b、$cのいずれも、オブジェクトID #01 のオブジェクトを値として持っているので。
「$a->a_ = 10;$b->b_ = 20;$c->c_ = 30;」はいずれも「オブジェクトID #01への操作」となったこと
という、この2つの区別をしっかりと頭に理解させておきましょう。

大分長くなってしまいましたが…次回「配列の参照」の続きを再開していきたいと思います。

バックナンバーはこちら

IT系のお仕事特集

お仕事のご紹介には、まずヒューマンリソシアへの登録が必要です。
ヒューマンリソシア人材派遣サイトの便利な機能 ・お気に入りの派遣求人のブックマーク ・登録会への予約 ・有給休暇の管理 ・WEB給与明細の確認 ・お気に入りの情報をメール受信
登録会の入力手続きをあらかじめおこなえます。

ヒューマンリソシア派遣サービスに 登録する 無料

ページトップへ戻る
ヒューマンリソシア派遣サービスに 登録する 無料
ページトップへ戻る