PHPのオブジェクトと参照渡し
![](https://thinkit.co.jp/sites/default/files/styles/main_image_730x/public/main_images/5520_main_8.png?itok=0hDlNmsQ)
こんにちは。ついに第4回目となりました、今回は、オブジェクトと参照渡しについてです。
オブジェクト指向を理解されている方には簡単だと思われるオブジェクトの扱いですが、PHP技術者認定試験では「これどうなるんだっけ?」と思うような書き方のプログラムがよく出題されます。
オブジェクトの振る舞いを踏まえて、実行結果がどうなるか問うようなパターンが多くみられるため、似たような出題のされ方をする参照渡しと合わせて見ていきましょう。
参照渡し
通常では関数の引数として渡した変数の値を関数の中で変化させても、元の変数には変化がありません。例を見てみましょう。
4_1.php
<?php function sampleFunction($foo){ $foo++; } $bar = 1; sampleFunction($bar); echo $bar;
出力結果
>php 4_1.php 1
![4_1.php](/sites/default/files/552001.png)
図1:4_1.php
ですが、関数を定義する際に&(アンパサンド)を引数の前につけることで、関数の中から関数の外にある変数の値を変化させることができます。
4_2.php
<?php function sampleFunction(&$foo){ $foo++; } $bar = 1; sampleFunction($bar); echo $bar;
出力結果
>php 4_2.php 2
![4_2.php](/sites/default/files/552002.png)
図2:4_2.php
4_2.phpのような使い方を、参照渡し(またはリファレンス渡し)と言います。通常だと、関数に渡された引数に関数内で別の値が代入されても、関数外の変数には影響がありません。
変数にはそれぞれ有効範囲(スコープ)があり、その有効範囲外では利用できないからです。そのため、関数の外で定義された変数を、関数の中で利用しようと思ってもできません。ただPHPでは定義していない変数は空の変数として扱うことができるので、正確には変数自体は利用できますが、空の状態になります。
一般的に、PHPでは関数に渡した引数は変数そのものではなく、値が渡されます。そのために、関数内で別の値が代入されても関数外の変数には影響がないのです。
PHP技術者認定上級試験では、こういった参照渡しを使って「書き方的に問題がないか」、「変数がどのように扱われるか」といったことを問う問題がしばしば出題されます。前者は、参照渡しにもいくつか書き方のパターンがありますので、どういった書き方があるのかを理解しておくと良いでしょう。後者については、前者を理解した上でしっかりコードを読めば、おのずと答えが出るはずです。
それではこういった書き方はどうでしょう。
4_3.php
<?php function sampleFunction($foo){ $foo++; } $bar = 1; sampleFunction(&$bar); echo $bar;
出力結果
>php 4_3.php Deprecated: Call-time pass-by-reference has been deprecated; If you would like to pass it by reference, modify the declaration of sampleFunction(). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file in D:\xampp\htdocs\test\php_col\4\4_3.php on line 7 2
4_3.phpの例のように、関数呼び出し時に参照渡しをする方法は、以前は良く使われていました。特にPHP4の頃は、頻繁に使われていたように感じます。
このように呼び出し時に参照渡しをする方法を、“call-time pass-by-reference”と呼びます。この方法はPHP5.3では非推奨となり、PHP5.4からは機能自体が削除されているため、使えなくなっています。ただ、現在のPHP技術者認定試験ではPHP5.3をベースとして出題されているため、「非推奨のエラーが出るが使える」ということを覚えておきましょう。
参照については、これ以外に関数の戻り値自体を参照で返すという書き方もあります。
4_4.php
<?php class test{ $foo = 1; function &getFoo(){ return $this->foo; } } $test = new test(); $result =& $test->getFoo(); $test->foo = 5; echo $result;
出力結果
>php 4_4.php 5
これを「リファレンス構文」といいます。リファレンス構文でない普通の関数は、毎回コピーを作成するためメモリの無駄であるとして、リファレンス構文をオススメする人もいます。しかし、PHPマニュアルにも「パフォーマンスを向上させるためだけの目的でこの機能を用いることはやめてください。そのようなことをしなくても、PHPエンジンが自動的に最適化を行います。」と書いてありますので、こういった考えで、リファレンス構文を使うのは間違いです。
ただし、試験では実行結果が正しいかどうかを問われることが多いため、適切かどうかはともかくとして、動くということは認識しておく必要があるでしょう。
さきほど変数にはスコープがあるため、関数内の変数に値を代入しても関数外の変数には影響がないと言いましたが、PHPにはスコープの範囲を広げる方法が用意されています。それが、globalという修飾子です。
global $bar;
上記のように使用すると、その変数のスコープをPHPプログラム全体に広げます。
4_5.php
<?php function sampleFunction(){ global $bar; $bar++; } $bar = 1; sampleFunction(); echo $bar;
出力結果
>php 4_5.php 2
こういった参照渡しによって変数にどう影響があるか、global修飾子によってスコープがどのようになるかは把握しておきましょう。