• PHP
【php8上級/準上級試験】模擬問題解説 問題6. &参照(リファレンス)unset()

「第1回 PHP 8 上級 模擬試験」を解説していきます

本記事ではひたすら下記記事の模擬試験の解説をしていきたいと思います!

第1回 PHP 8 上級 模擬試験
https://study.prime-strategy.co.jp/study/ph8ex1/

解説記事一覧

模擬問題 6

リファレンスに関する説明の中で、誤っているものを1つ選びなさい。
なお、すべてのコードの先頭には下記のコードが書かれているものとする。

declare(strict_types=1);
error_reporting(-1);

PHP のリファレンスを使うと、ふたつの変数が同じ内容を指すようにできる。
そのため、以下のコード

$s = 'string';
$s2 = &$s;
$s2 = $s2 . ' add';
echo $s;

は正しく実行でき、結果は string add となる。

下記のコードの理解がポイントです!

$s2 = &$s;

この行では、$s2$s参照 を代入しています。

つまり、$s2$sエイリアス(別名) となり、$s2 に対する変更は $s にも反映されます(逆も同じ)。

よってこの選択肢は⭕正しいです

PHP のリファレンス渡しを使うと、関数内でその引数を修正可能になる。
リファレンス渡しは、呼び出す側で変数に & を付ける必要がある。
& を付けずに呼び出すと、リファレンス渡しにならない。
そのため、以下のコード

function hoge($s) {
    $s = $s . ' add hoge';
}

$s_hoge = 'string';
hoge($s_hoge);
hoge(&$s_hoge);
var_dump($s_hoge);

は正しく実行でき、結果は string(15) “string add hoge” となる。

関数のリファレンス渡しについて

(✅ そもそも リファレンス渡しとは、関数の引数を 「参照できるものにする」 こと、逆は値渡し:デフォルト)

「呼び出し側で & を付ける必要がある」は誤り
「関数の定義側で & を付ける必要がある」が正しい

つまり選択肢は誤り❌となります

PHPのリファレンス返しを使うと、関数の戻り値にリファレンスを指定する事が出来る。
リファレンス返しは、「関数の定義」と「代入」の双方に & を付ける必要がある。
そのため、以下のコード

class hoge {
    public function &test() {
        return $this->s;
    }

    private $s = 'string';
}

$obj = new Hoge();
$s = &$obj->test();
$s = $s . ' add';
var_dump($obj);

は正しく実行でき、結果は次のとおりとなる。

object(hoge)#1 (1) {
  ["s":"hoge":private]=>
  &string(10) "string add"
}

なお、マニュアルには「パフォーマンスを向上させるためだけの目的でこの機能を用いることはやめてください。そのようなことをしなくても、PHPエンジンが自動的に最適化を行います」と記されている。

PHPのリファレンス返しとは?

「リファレンス返し」 とは、関数の戻り値を 参照として返す 方法。
リファレンス返しを使うと、関数の戻り値を直接変更できるようになる。

<使用手順>

  1. 関数の定義時に & を付ける
public function &test() { ... }
  1. 代入時にも & を付ける
$s = &$obj->test(); // ← 代入時にも & を付ける

問題文を見てみると

$obj に Hoge のインスタンスを作成し、プロパティ $s は ‘string’ となる。

⬇️

$s = &$obj->test();
  • & を付けることで $s は $obj->s の参照になる。
  • つまり、$s を変更すると $obj->s も変更される。

⬇️

$s = $s . ' add';

$s に ‘ add’ を追加すると、$obj->s も変更される。

⬇️

$obj->s は ‘string add’ に変更されている。

よって選択肢は正しい⭕です

リファレンスは、unset を使うことで解除する事が出来る。
そのため、以下のコード

$s = 'string';
$s2 = &$s;
$s2 = $s2 . ' add';
var_dump($s, $s2);
unset($s2);
$s2 = $s2 . ' add2';
var_dump($s, $s2);

を実行すると、次のとおりとなる。

string(10) "string add"
string(10) "string add"
Warning: Undefined variable $s2 in ...
string(10) "string add"
string(5) " add2"

変数への参照と unset() の挙動

下記で参照が解除されます

unset($s2);

つまり「$s への参照」が解除され、$s2 自体が未定義状態(存在しない状態) となります。

⬇️

未定義変数は “” (空文字列) として評価されるため、最終的には $s2 に “” . ‘ add2’ が代入されます。つまり ‘ add2’ が格納されます。

var_dump($s, $s2);

// unset後の出力結果
string(10) "string add"
string(5) " add2"

よって選択肢⭕正解です