【やさしく解説】PHP8上級試験の模擬問題(12)

PHP
スポンサーリンク

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

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

PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/ 

問題文

PHP 7.0.x から PHP 7.1.x への移行 に関する説明の中で、誤っているものを1つ選びなさい。
なお、すべてのコードの先頭には下記のコードが書かれているものとする。

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

(1)
配列の短縮構文 ([]) を使って、 代入用に配列の値を取り出せるようになった。
これは、list() の代替として使う事ができる(list() が無くなったわけではない)。そのため、以下のコード

$data = [
  [1, 2],
  [777, 999],
];

list($i, $j) = $data[0];
var_dump($i, $j);
[$i, $j] = $data[1];
var_dump($i, $j);


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

int(1)
int(2)
int(777)
int(999)

(2)
新しい擬似型 (callable と同じような型) である iterable が導入された。パラメータおよび返り値の型指定で使うことができ、「配列か、あるいは Traversable インターフェイスを実装したオブジェクトを受け付ける」ようになる。そのため、以下のコード

function hoge(iterable $itr) {
  var_dump($itr);
}

hoge([1, 2]);
hoge(new ArrayObject());


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

array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}
object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(0) {
  }
}


一方で以下のコード

function hoge(iterable $itr) {
  var_dump($itr);
}

$obj = new stdClass();
$obj->s = 'string';
$obj->i = 999;
hoge($obj);


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

Fatal error: Uncaught TypeError: Argument 1 passed to hoge() must be iterable, object given, called in …

(3)
数値形式ではない文字列を使って、数値を期待する演算 (+, -, *, /, **, %, <<, >>, |, &, ^ や、これらを用いた代入演算) を行おうとしたときに、 E_WARNING あるいは E_NOTICE レベルのエラーが発生するようになった。そのため、以下のコード

$i = '11' + '22';
var_dump($i);


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

int(33)


一方で以下のコード

$i = '11' + 'a';
var_dump($i);


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

Warning: A non-numeric value encountered in …
int(11)

(4)
文字列操作関数 のうちオフセット指定のできるものすべてについて、負のオフセットを指定できるようになった。
[] や {} による 文字列への文字単位のアクセス についても同様となり、負のオフセットは、文字列の末尾からのオフセットと解釈される。
負の値を渡した場合、-0 が「文字列の末尾」となる。そのため、以下のコード

$s = 'abcdefg';
var_dump( $s[-1] );

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

string(1) "f"

解説

選択肢1の解説

正しいです。
PHP 7.1 からは、[] を使って配列の値を取り出す構文が追加され、list() の代替として使うことができます。

list()について説明します。
PHPでは、複数の変数に配列の値を一気に代入したいときに list() を使います。

$data = [1, 2];
list($a, $b) = $data;
// $a = 1, $b = 2

これはPHP 5の頃から使われていた機能です。

一方、PHP 7.1では「配列の短縮構文での代入」が追加されました。
PHP 7.1からは、次のような「短縮構文」(= 配列のリテラルのような形)でも同じように代入できるようになりました。

[$a, $b] = [1, 2];
// $a = 1, $b = 2

つまり、list() とほぼ同じ意味ですが、より自然な配列っぽい書き方です。

list()の代替として短縮構文([])が使えるようになっていますが、list() が無くなったわけではありません。このため、選択肢1は正しいといえます。

選択肢2の解説

正しいです。
PHP 7.1 で新しい擬似型 iterable が導入され、iterable は配列や Traversable インターフェイスを実装したオブジェクトを受け付けます。

iterable は PHP 7.1 で追加された擬似型(型ヒント)です。これは、関数の 引数 や 返り値 に使えて、①配列(array)、②Traversable を実装したオブジェクトの どちらでも受け取れる 型を表します。

実際のコードを見てみましょう。まずは①配列について。

function hoge(iterable $itr) {
  var_dump($itr);
}
hoge([1, 2]);

この書き方はOKです。これはvar_dumpされると

array(2) {
  [0] => int(1)
  [1] => int(2)
}

が表示されます。

次に、②Traversable実装オブジェクト(ArrayObject)です。

hoge(new ArrayObject());

ArrayObject は内部的に Traversable を実装しているのでこれも OKです。var_dumpされると、

object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(0) {
  }
}

これは中が空な ArrayObject ですね。

次に、ただのオブジェクト(stdClass)を見てみましょう。

$obj = new stdClass();
$obj->s = 'string';
$obj->i = 999;
hoge($obj);

これはNGです。stdClass は「ただの汎用オブジェクト」であり、Traversable を実装していないので iterable として渡せません。次のようなエラーになります。

Fatal error: Uncaught TypeError:
Argument 1 passed to hoge() must be iterable, object given

これらのことからこの選択肢は正しいことが書かれています。

選択肢3の解説

正しいです。
PHP 7.1 では、数値形式ではない文字列に対して演算を行うと E_WARNING または E_NOTICE が発生するようになりました。

PHPは「ゆるい型(動的型付け)」を持つ言語です。
数値として書かれていない文字列でも、自動的に数値として解釈しようとします。例えば、

echo '11' + '22'; 
// 出力は 33(自動的に数値として扱われる)

以前のバージョン(PHP 7.0 まで)では、数値じゃない文字列を加算しても、警告は出ませんでした。たとえば ’11’ + ‘a’ は「11 + 0」と解釈されて、11 になるという具合です。

PHP 7.1 からは、数値ではない文字列を演算に使うと、E_WARNING レベルの警告が出るようになりました。(ただし、処理は続行され、結果はちゃんと表示されます。)

よってこの選択肢には正しいことが書かれています。

選択肢4の解説

誤っています。
-0 は文字列の末尾を指しません。-1 が末尾を指し、-0 は無効でエラーを引き起こします。

PHPの文字列とオフセットアクセスについて説明します。

$s = 'abcdefg';
echo $s[0]; // a
echo $s[1]; // b

このように、[] を使って文字列中の「n文字目」を取り出せます。

PHP 7.1 からは、$str[-1] のような負のオフセットが使えるようになりました。-1 は「末尾の1文字前」(つまり最後の文字)を意味します。-2 は「最後から2文字目」といった具合です。

問題文を見ると、以下のようなコードとなっており、

$s = 'abcdefg';
var_dump( $s[-1] );

これは ‘g’を指しますので、選択肢4は誤りです。

正解選択肢

以上より選択肢が正解4となります。

コメント

タイトルとURLをコピーしました