SlideShare a Scribd company logo
1 of 19
値渡しと参照渡しの比較
2012/02/18 by kitoku_magic
軽く自己紹介

IT 業界歴 3 年半のエンジニア

PHP は、業務ではまだ使ったことないので、
勉強兼ねて自作で MVC フレームワーク作っ
てる

オブジェクト指向が好き ( 保守性に優れてい
る為 )

自分よりエロい人を見たことないぐらいエロ
い w 特に下半身フェチ w
本題

軽くブログの内容をおさらい
・値渡し後に引数の値を変えると、呼び出し元
の値を維持する為に値のコピーが行われ時間
がかかる
・よって、引数の値を変える場合には、参照渡
しかオブジェクト指向のカプセル化 ( セッ
ター ) を使うと良い
引数のデータ型は関係あるか?

boolean 、 float 、 int 、 NULL 、 object は、参照
渡しの方が速いが気になるレベルの差でもな
いと思う

resource は差が出なかった。値の変更
は、 fopen で違うファイルを読むとしたのが
原因か?

string と配列 ( 数値か連想問わず )
は、 length( 文字数や要素数 ) が多いほど、参
照渡しの方が有利になる
文字列と配列が顕著なのは何故?

値を格納するメモリ領域のサイズが可変だからっぽい

例えば int だと、値が 0 でも int_max でも確保するメ
モリ領域のサイズは変わらないが、文字列 ( 文字の配
列 (PHP も C 言語と同じっぽい )) と配列 ( 数値か連想
問わず ) だけは、文字数や要素数によって、サイズが
変わる

int などでも時間差は発生するが、メモリ領域
のサイズが変わらないので、微々たる差に留
まる
← よって、文字列と配列の時に特に注意
処理の何処で時間がかかるのか?

引数の値を変える「瞬間」 ( コピーオンライトという
仕組み )

値渡しだと、関数の呼び出し元の値を保持する為、値
のコピーが行われるが、コピーが行われるタイミング
は、引数を渡した瞬間では「ない」

だから値渡しでも、その引数の値を操作しな
ければ、時間はかからない

コピーにかかる時間は、メモリ領域のサイズ
の大きさに比例する ( だから文字列と配列が
注意 )
サンプルプログラムその1
function 関数名 ($ 引数 A, $ 値 A) {
$ 引数 A = $ 値 A;← このタイミングで値のコピーが行われるので、この行の処理に時間がかかる
return $ 引数 A;
}
function 関数名 ($ 引数 A, $ 値 A) {
$ 変数 A = $ 引数 A;← この場合は、値を変更していないので、値のコピーは行われず、時間もかからない
return $ 変数 A;
}
function 関数名 ($ 引数 A, $ 値 A) {
$ 変数 A = $ 引数 A;
$ 変数 A = $ 値 A;← これでも引数 A の値のコピーが行われる。変数 A と引数 A で同じメモリ領域を見てる?
return $ 変数 A;
}
サンプルプログラムその2
class クラス名 {
public function メソッド名 ($ 引数 A, $ 値 A) {
$ 引数 A = $ 値 A;← メソッドにしても所詮は値渡しされた引数の中身を変えているので結果は変わらない
return $ 引数 A;
}
}
$ 変数 A = 値 B;
$ 変数 B = new クラス名 ();
$ 変数 A = 変数 B-> メソッド名 ($ 変数 A, 値 C);
サンプルプログラムその3
class クラス名 {
public function コンストラクタ () { $this->init(); }
public function init() { $this->set_ 変数 A(null); }
public function set_ 変数 A($ 変数 B) { $this-> 変数 A = $ 変数 B; }
public function get_ 変数 A() { return $this-> 変数 A; }
public function メソッド名 ($ 値 A) { $this-> 変数 A = $ 値 A; }
private $ 変数 A;
}
$ 変数 C = new クラス名 ();
$ 変数 C->set_ 変数 A( 値 B);
$ 変数 C-> メソッド名 ( 値 C);
// 値を取得したければ「 $ 変数 C->get_ 変数 A() 」
値渡ししていても、その引数の中身を操作していないので問題ない
で、終わりのはず
が・・・
ブログ記事のはてブにこんなのが
理屈では知っていても、結果を
見ると改めて驚かされます
ね。ただ速度を考慮しないの
であれば、参照渡しとか破壊
系のメソッドとかは使いたく
ないしなぁ。
← 破壊系のメソッドってなぁ
破壊系のメソッド

オブジェクトの内部状態 ( 値 ) を変えてしま
うメソッド

Ruby に多いみたい

例えば、「 $str = 'a'; 」の時、「 $str-> 小文
字を大文字に変えるメソッド (); 」を実行し、
「戻り値がない」のに、 $str が 'A' になる様
なメソッド

つまり、自分で自分のクラスのメソッドを呼
んでるのに、自分の内部状態を変えてしまう
メソッド ( ミュータブル的とも言う )
非破壊系のメソッド

オブジェクトの内部状態 ( 値 ) を変えないメ
ソッド

さっきと逆で、内部状態を変えたい時には、
戻り値が必要

例えば、「 $str = 'a'; 」の時、「 $str = $str->
小文字を大文字に変えるメソッド (); 」を実行
すると、 $str が 'A' になる様なメソッド

つまり、自分で自分のクラスのメソッドを呼
ぶだけでは、自分の内部状態は変わらないメ
ソッド ( イミュータブル的とも言う )
で・・・

破壊的 ( ミュータブル的 ) と参照渡しとオブ
ジェクト指向

非破壊的 ( イミュータブル的 ) と値渡しと非
オブジェクト指向

これらって似てないか?

前者はオブジェクトの状態が「変わる」が、
後者は「変わらない」って角度で見たときに
イミュータブルなクラスのサンプ
ル
final class クラス名 {
public function コンストラクタ ($ 変数 A) { $this-> 変数 B = $ 変数 A をディープコピーする ; }
public function get_ 変数 B() { return $ 変数 B をディープコピーする ; }
public function メソッド名 ($ 値 A) { new 自分のクラス名 ($ 値 A); }
private final(PHP は変数に final 書けないけど ) $ 変数 B;
}
$ 変数 C = new クラス名 ( 値 B);
$ 変数 C-> メソッド名 ( 値 C);
// 値を取得したければ「 $ 変数 C->get_ 変数 A() 」
値渡しした引数の中身を変えていない ( というか final だと変えれない ) ので、速度は低下しない
ミュータブルとイミュータブルの
比較
・イミュータブル
メリット:
1.変数の値 ( オブジェクトの状態 ) の変化に気を使う必要がないので使いやすい
デメリット:
1. ( 値渡しは ) 複数の戻り値を返しにくい
2. ( 値渡しは ) 値のコピーに処理時間がかかる
3. ( イミュータブルは ) 不変なので、値を変えたい時には新たにインスタンスを生成しなければならない ( コスト的にどうか )
4. ( イミュータブルは )final なので継承が出来ない。よって拡張性に欠ける
ミュータブルとイミュータブルの
比較
・ミュータブル
メリット:
1. ( 参照渡しは ) 複数の戻り値を返しやすい
2.引数は「 ( 多分 ) メモリのアドレスを参照しているだけなので実態をコピーする必要がなく」処理時間がかからない
3.値を変えたい時に、インスタンスを生成する必要がない
4. final じゃないので、継承したりして拡張出来る
デメリット:
1.引数の値 ( オブジェクトの状態 ) の変化に気を使う必要があるので使いにくい
とはいえデメリットについて。
値を変えたい変数は引数で渡さずに、必ずセッター経由で値を変える様にすると、
セッター内でデバッグすれば ( どのファイルのどの行から呼ばれたかを調べる ) きっちり監視できる
ミュータブルの方が良い別の理由

ソフトウェアは、機能追加や改修により「成
長」していくもの ( アジャイルが典型的 )

保守性の高さがウリと思う、オブジェクト指
向 ( つまりミュータブル ) は、そういった意
味でソフトウェア開発に合っていると考える

だから、ミュータブルの方が良いと思う

といっても、イミュータブルの方が良い時が
ある可能性も否定はしない ( どういう時かは
不明 )
結論

ミュータブルの方が扱いが難しいかもしれな
いが、頑張って勉強して使いこなそう!

イミュータブルも、使える局面があった時に
使える様に勉強はしておこう!

今回の話が、皆さんのより良いソフトウェア
開発ライフの一助になれば幸いです

More Related Content

Similar to 値渡しと参照渡しの比較

クラスのインスタンス変数について
クラスのインスタンス変数についてクラスのインスタンス変数について
クラスのインスタンス変数についてTomoya Kawanishi
 
「エクストリームエンジニアへの道(Swift編)」
「エクストリームエンジニアへの道(Swift編)」「エクストリームエンジニアへの道(Swift編)」
「エクストリームエンジニアへの道(Swift編)」tech-arts
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26Yoshihisa Ozaki
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングkunihikokaneko1
 

Similar to 値渡しと参照渡しの比較 (6)

クラスのインスタンス変数について
クラスのインスタンス変数についてクラスのインスタンス変数について
クラスのインスタンス変数について
 
「エクストリームエンジニアへの道(Swift編)」
「エクストリームエンジニアへの道(Swift編)」「エクストリームエンジニアへの道(Swift編)」
「エクストリームエンジニアへの道(Swift編)」
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26C# コーディングガイドライン 2013/02/26
C# コーディングガイドライン 2013/02/26
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
 

値渡しと参照渡しの比較