
PHP8 上級/準上級試験の認定模擬問題として、プライム・ストラテジー様のPRIME STUDYが認定されているようです。ただ、この模擬問題には解説がありませんので解説をまとめていこうと思います。シリーズ第6回目です。

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。

今回はリファレンスについての問題です。PHPにおける参照(リファレンス)の仕組みや、参照渡し・返しによる挙動の違いについて問われる内容です。値の保持・変更に影響する重要な概念なので、基本構文とともに動作の流れを丁寧に確認しておきましょう。
PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/
問題文
リファレンスに関する説明の中で、誤っているものを1つ選びなさい。
なお、すべてのコードの先頭には下記のコードが書かれているものとする。
declare(strict_types=1);
error_reporting(-1);
(1)
PHP のリファレンスを使うと、ふたつの変数が同じ内容を指すようにできる。
そのため、以下のコード
$s = 'string';
$s2 = &$s;
$s2 = $s2 . ' add';
echo $s;
は正しく実行でき、結果は
string add
となる。
(2)
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"
となる。
(3)
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エンジンが自動的に最適化を行います」と記されている。
(4)
リファレンスは、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"
解説
選択肢1
正しいです。
参照(リファレンス)に関する問題です。PHPのリファレンス(参照)とは、変数の「値」ではなく「アドレス(メモリ上の位置)」を共有する仕組みです。通常、変数を代入すると、値のコピーが作成されますが、リファレンスを使うと、同じデータを複数の変数から操作できます。
コードを1行ずつ 見ていきましょう。
(1行目)「$s = ‘string’;」で変数 $s に 文字列 “string” を代入しています。
(2行目)「$s2 = &$s;」で、$s2 を $s の 参照 にする。つまり、$s と $s2 は同じデータを指すようになります。
(3行目)「$s2 = $s2 . ‘ add’;」で、$s2 に「現在の $s2 の内容に ‘ add’ を足したもの」を代入します。ですが $s2 は $s の参照なので、$s も同じ内容になります。ここがポイントです。
(4行目)「echo $s;」で $s の内容を出力すると “string add” になります。
選択肢2
誤っています。
リファレンス渡しの方法が間違っています。引数をリファレンス渡しする場合、関数の定義で引数に & を付ける必要があります。
すが、この選択肢コードでは関数 hoge の定義に & が付けられていません。
選択肢3
正しいです。
PHPでは、関数の戻り値としてリファレンスを返すことができます。これにより、関数の戻り値を直接変更できるようになります。これが「リファレンス返し」です。
リファレンス返しのわかりやすい例を挙げてみます。
function &getValue() {
static $value = 10;
return $value; // 変数 $value のリファレンスを返す
}
$num = &getValue(); // リファレンスとして受け取る
$num = 20; // 返されたリファレンスを変更
echo getValue(); // 出力: 20
関数の定義時に & を付ける(1行目)のと、呼び出し時も & を付けて受け取る(6行目)というところがポイントです。
リファレンスは便利ですが、使いすぎるとバグの原因にもなりますので、本当に必要かを考えながら使用する必要があります。
選択肢4
正しいです。
unset を使うことでリファレンスを解除することができます。これにより、リファレンスが切れて、元の変数と独立した状態になります。
5行目の unset($s2); を実行すると、$s2 は削除されるだけで、$s はそのまま残る という点が重要です。つまり、unset は「変数そのものを削除する」だけで、元の変数 $s の値には影響を与えません。
解除後に操作しようとすると未定義の変数エラーが発生します。
正解選択肢
以上より選択肢2が正解となります。
他の問題へ
模擬問題(1)インストール
模擬問題(2)変数の型
模擬問題(3)クラス
模擬問題(4)メソッドその1
模擬問題(5)メソッドその2
模擬問題(6)リファレンス
模擬問題(7)名前空間
模擬問題(8)エラー
模擬問題(9)定義済みのインターフェイスとクラスおよび SPL インターフェイス
模擬問題(10)SPL
模擬問題(11)定義済の変数
模擬問題(12)PHP7.0.xからPHP7.1.xへの移行
模擬問題(13)可変変数
模擬問題(14)PHP7.3.xからPHP7.4.xへの移行
模擬問題(15)PHP7.4.xからPHP8.0.xへの移行
模擬問題(16)制御構造
模擬問題(17)XSS(クロスサイトスクリプティング)
模擬問題(18)ファイルアップロード
模擬問題(19)推測困難なトークン
模擬問題(20)セッション
模擬問題(21)PHP のメモリ消費
模擬問題(22)関数その1
模擬問題(23)関数その2
模擬問題(24)関数その3
模擬問題(25)関数その4
模擬問題(26)関数その5
模擬問題(27)関数その6
模擬問題(28)関数その7
模擬問題(29)関数その8
模擬問題(30)関数その9
コメント