PHP8上級資格取得へ向けたアウトプット記事になります。
PHP試験運営団体より公開されている模擬試験を1つ1つみていく形で事細かくみていきますが、勉強途中ゆえ間違っている部分に関してはご了承ください。
PHP上級資格のメイン教材はPHPマニュアルと指定されていますので、このマニュアルを主に踏襲した内容となっています。
試験問題1-2 | 模擬試験を解く#1 |
---|---|
試験問題3 | 模擬試験を解く#2 |
試験問題4 | 模擬試験を解く#3 |
試験問題5 | 模擬試験を解く#4 |
試験問題6 | 模擬試験を解く#5 |
試験問題7 | 模擬試験を解く#6 |
本記事 | 模擬試験を解く#7 |
主な勉強教材は以下になります。
1.独習PHP第4版
2.はじめてのPHP
3.PHP公式マニュアル
PHP8上級試験模擬問題
試験問題8
エラーに関する説明の中で、誤っているものを1つ選びなさい。
なお「¥」はバックスラッシュに読み替えること。
また、すべてのコードの先頭には下記のコードが書かれているものとする。
declare(strict_types=1);
error_reporting(-1);
下記はマニュアルから一部引用した内容である。
Exception implements Throwable { }
Error implements Throwable { }
選択肢?
PHPで「何をエラーとして出力し、何をエラーとして出力しないか」の制御は、php.ini
の error_reporting
で行う。
プログラム実行時に ini_set()
関数を使っても設定できるが、error_reporting()
という専用の関数も存在する。
ここには定数 (E_ERROR
や E_NOTICE
など) を、複数指定する場合はビット和演算子等をつかって指定する事が多い。値は int
のため直接数値を入れてもよいが、定数を使う事が推奨されている。
定数には色々あるが、数値で 0
を指定すると「全てのエラー出力をオフにする」事ができる。
error_reporting()
関数で -1
を渡す事があるが、これは「将来のバージョンの PHP で新しいレベルと定数が追加されたとしてもすべてのエラーを表示するようになる (2の補数で、-1は「全てのbitが立つ」値になる)」という意味で使われる。
そのため、以下のコード
error_reporting(0);
$i++;
var_dump($i);
error_reporting(-1);
$j++;
var_dump($j);
を実行すると、結果は次のとおりとなる。
int(1)
Warning: Undefined variable $j in ...
int(1)
「error_reporting」と「ini_set()」に関しては以下の記事の問題文についての箇所で説明しています。
ここでのポイントは値に-1を指定した時のerror_reportingの挙動です。
下記コードの場合は、仮に将来のバージョンの PHP で新しいレベルと定数が追加されたとしてもすべてのエラーを表示するようになります。
// 全ての PHP エラーを表示する
error_reporting(E_ALL);
// 全ての PHP エラーを表示する
error_reporting(-1);
よって、この選択肢は合っています。
選択肢?
set_error_handler()
を使うと、ユーザー定義のエラーハンドラ関数を設定する事ができる。
これを使うと「致命的なエラーの際になんらかの後処理が必要な場合」などにその処理を記述できる。
また、書き方によっては「PHP の標準関数のエラー時に、例外を投げる事」や「E_NOTICE
であっても例外を投げる」事も可能である。
そのため、以下のコード
set_error_handler(
function ($errno, $errstr, $errfile, $errline) {
if (0 !== $errno & error_reporting()) {
throw new ErrorException( $errstr, 0, $errno, $errfile, $errline);
}
}
);
try {
$i++;
} catch(¥Throwable $e) {
echo 'catch Exception', PHP_EOL;
echo $e->getMessage(), PHP_EOL;
}
を実行すると、結果は次のとおりとなる。
catch Exception
Undefined variable $i
まず例外クラスについて深掘ります。
「Throwableクラス」はすべての例外クラスのルートクラスであり、「Errorクラス」と「Exceptionクラス」がサブクラスとして存在しています。
PHPのクラスがThrowableインターフェイスを直接実装することはできません。そのかわりに、Exceptionを継承する必要があります。
catch句がThrowableクラスの場合、tryブロック内でスローされたErrorとExceptionが捕捉されます。
try{
}catch(?Throwable $e){
}
またcatchブロックで渡された変数$eを介して例外に関するさまざまな情報にアクセすることができます。
メソッド | 概要 |
---|---|
getMessage( ) | 例外メッセージ |
getCode( ) | 例外コード |
getLine( ) | 例外が発生した行数 |
getFile( ) | 例外が発生したファイル名 |
getPrevious( ) | 前の例外 |
getTrace( ) | バックトレース(配列) |
getTraceAsString( ) | バックトレース(文字列) |
また、Exceptionクラスには紛らわしいですがErrorExceptionクラスがあります。
ErrorExceptionクラスは、set_error_handler()関数と併用することで「特殊な変換処理」で変換するためだけに存在するクラスです。
旧来のエラーは「Throwable」ではないため、catch句では補足することができません。
旧来のエラーには以下のようなものがあります。
Parse Error | コードが文法的に誤っている時に発生。一切の処理を行わない |
---|---|
Fatal Error | 処理を継続することが不可能の場合に発生。発生した箇所で処理停止 |
Warning | 処理継続は可能だが、想定外の問題が起こったときに発生 |
Notice | 処理継続は可能だが、想定外の問題が起こったときに発生 |
以下のコードは、定義していない変数をインクリメントしようとしているために「PHP Warning: Undefined variable $i
」が出力されるところをcatch句で捕捉し、set_error_handler()によってエラーメッセージをErrorExceptionに変換しています。
set_error_handler(
function ($errno, $errstr, $errfile, $errline) {
throw new ErrorException('エラーの原因: ' . $errstr, 0, $errno, $errfile, $errline);
}
);
try{
$i++;
}catch(\Throwable $e){
echo 'catch Exception', PHP_EOL;
echo $e->getMessage(), PHP_EOL;
}
/**出力結果
catch Exception
エラーの原因: Undefined variable $i
*/
ちなみにこちらでは「Fatal Error」を受け取ることができないため、どうしても対処したい場合は「register_shutdown_function()」を使用する必要があります。
選択肢のコードでは「E_WARNING」レベルのため本来はcatch句のThrowableでは捕捉できないですが、set_error_handler()によって捕捉されエラーメッセージを出力しています。
よって、この選択肢は合っています。
参考記事:Qiita
選択肢?
PHPのエラーのうち、E_ERROR
は「重大な実行時エラー」、E_PARSE
は「コンパイル時のパースエラー」となり、いずれもスクリプトの実行は中断される。
一方で、E_WARNING
「実行時の警告 (致命的なエラーではない)」とE_NOTICE
「実行時の警告」は、スクリプトの実行は中断されない。
そのため、以下のコード
$i++;
var_dump($i);
echo 'fin.';
を実行すると、結果は次のとおりとなる。
Warning: Undefined variable $i in ...
int(1)
fin.
問題文でerror_reporting(-1)が先頭に記述されていると前書きがあるため、選択肢のコードでは「PHP Warning: Undefined variable $i in
」が出力され、スクリプトの実行は中断されません。
よって、この選択肢は合っています。
選択肢?
PHP 5 において、Exception
クラスは全ての例外の基底クラスであった。PHP 7 において、Exception
クラスは「Throwable
インタフェース」を基底クラスとしている。
また、PHP 7 以降において Error
クラスという「PHP のすべての内部エラーの基底クラス」ができた。
そのため、以下のコード
try {
throw new ¥Exception('Exception');
} catch(¥Throwable $e) {
echo 'catch ' , $e->getMessage();
}
を実行すると、結果は catch Exception
?となる。
同様に、以下のコード
try {
throw new ¥Error('Error');
} catch(¥Exception $e) {
echo 'catch ' , $e->getMessage();
}
を実行すると、結果は catch Error
となる。
選択肢?の解説からErrorクラスおよびExceptionクラスはそれぞれThrowableクラスのサブクラスであって、ErrorクラスとExceptionクラスには親子関係はありません。
そのため、この選択肢は誤りです。