こんにちは。PHP技術者認定機構 CTOの古庄道明です。
今日もPHP8上級試験の模擬問題と解説を紹介します。
以下を解いて出題のイメージと知識を補っていただけると幸いです。
問題
リファレンスに関する説明の中で、誤っているものを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"
回答と解説
問題は「リファレンス」についてです。
公式マニュアルの「リファレンス」のページを読んでおきましょう。
https://www.php.net/manual/ja/language.references.php
選択肢1を見ていきましょう。
PHP のリファレンスを使うと、ふたつの変数が同じ内容を指すようにできます。
https://www.php.net/manual/ja/language.references.whatdo.php
そのため
$s = 'string';
$s2 = &$s;
のコードだと、変数 $s2 は、変数 $s と同じ内容を指します。
その後で
$s2 = $s2 . ' add';
とやっているため、$s と $s2 は両方とも ‘string add’ という中身になります。
そのため
echo $s;
を実行するとstring addが出力されます。
したがってこの選択肢には正しいことが書かれています。
選択肢2を見ていきましょう。
PHP では、リファレンスにより関数に変数を渡すことが可能です。
https://www.php.net/manual/ja/language.references.pass.php
リファレンス渡しをする場合、関数宣言にリファレンス記号を書く必要があります。
そのため例えば以下のコード
function hoge(&$s) {
$s = $s . ' add hoge';
}
$s_hoge = 'string';
hoge($s_hoge);
var_dump($s_hoge);
を実行すると
string(15) "string add hoge"
となります。関数内の $s は、リファレンス渡しで渡されているため、上述のコードの $s_hoge と同じ内容を指しているからです。
しかし問題文のコードは、以下です。
function hoge($s) {
$s = $s . ' add hoge';
}
$s_hoge = 'string';
hoge($s_hoge);
hoge(&$s_hoge);
var_dump($s_hoge);
このコードは「関数宣言にリファレンス記号がなく」「関数呼び出しのところにリファレンス記号がある」状態です。
この場合、「関数呼び出しのところにリファレンス記号」でParse error: syntax error, unexpected token "&" in ...
のエラーが発生します。
したがってこの選択肢には誤りがあります。
選択肢3を見ていきましょう。
PHP のリファレンス返しを使うと、関数の戻り値にリファレンスを指定することができます。
https://www.php.net/manual/ja/language.references.return.php
リファレンス渡しと異なり、リファレンス返しをするためには、関数定義側と、戻り値を受け取る代入側の両方でリファレンス記号を使う必要があります。
そのため
class Hoge {
public function &test() {
return $this->s;
}
private $s = 'string';
}
$obj = new Hoge();
$s = &$obj->test();
$s = $s . ' add';
var_dump($obj);
のコードは正しく動き、リファレンス返しとなります。$s は $obj インスタンスのプロパティ $s と同じ内容を指し示すため、var_dumpの結果は
object(Hoge)#1 (1) {
["s":"Hoge":private]=>
&string(10) "string add"
}
となります。
したがってこの選択肢には正しいことが書かれています。
選択肢4を見ていきましょう。
リファレンスは、unset を使うことで解除することができます。
https://www.php.net/manual/ja/language.references.unset.php
同じ内容を指し示す2つの変数がある時に、片方をunsetしても、変数の内容は破棄されず、リファレンスが解除されるだけになります。
そのため
$s = 'string';
$s2 = &$s;
$s2 = $s2 . ' add';
var_dump($s, $s2);
でリファレンスの代入と文字列連結をした後で
unset($s2);
をすると、$s2 はリファレンスから外れ、変数としては未定義になります。
ただし、$s が指している内容そのものは破棄されないため、$s は 'string add' のままです。
そのため、上述の後に
$s2 = $s2 . ' add2';
var_dump($s, $s2);
とすると、$sは 'string add' のまま。
未定義の変数との文字列連結として「Warning: Undefined variable $s2 in …」が出力されたあと、$s2 には ' add2' が代入されます。
そのため出力全体としては
string(10) "string add"
string(10) "string add"
Warning: Undefined variable $s2 in ...
string(10) "string add"
string(5) " add2"
となります。
したがってこの選択肢には正しいことが書かれています。
選択肢2に誤りがあるため、解答は2になります。
PHP8上級試験と公式問題集に興味がある方は、以下のページをご覧のうえ、この機会に是非受験ください。
PHP8上級試験
https://www.phpexam.jp/summary/expert8
公式問題集:PHP8技術者認定上級試験公式問題集上巻
https://www.amazon.co.jp/dp/B0FQ1LTTQ4/
公式問題集:PHP8技術者認定上級試験公式問題集下巻ベータ
https://www.amazon.co.jp/dp/B0F7F4H8FP/
また、試験対策セミナーは毎月開催しています。興味がある方は以下のページをご覧いただき是非セミナーにもご参加ください。(フォローいただけるとセミナーのご案内が届くようになります)
PHP技術者認定機構の公式Peatixグループ
https://peatix.com/group/43424
www.phpexam.jp

