PHP Exceptionのpropertyにあるcodeはuser-defined error code
Introduction
仕事でPHPStanの修正をしている時、 Exception
classのconstructorでcodeを指定しているコードに出くわした。
Exception
におけるcodeの扱いについて記述している記事がなかったので php/php-src のコードにあたってみた。
簡易的な調査
Interface定義
php.netのUser Contributed Notesに以下のような記述がある。 https://www.php.net/manual/en/language.exceptions.php#91159
<?php
interface IException
{
/* Protected methods inherited from Exception class */
public function getMessage(); // Exception message
public function getCode(); // User-defined Exception code
public function getFile(); // Source filename
public function getLine(); // Source line
public function getTrace(); // An array of the backtrace()
public function getTraceAsString(); // Formated string of trace
/* Overrideable methods inherited from Exception class */
public function __toString(); // formated string for display
public function __construct($message = null, $code = 0);
}
code
とは User-defined Exception code
と書いてある通り、ユーザー側が任意の数値を入れられる。
PHPStanを実行すると以下のような型として認識されているようだ。
public function __construct(string $message = null, int $code = 0);
php-srcコードリーディング
Exceptionの定義は以下。
Zend/zend_exceptions.c#L303-L330:
/* {{{ Exception constructor */
ZEND_METHOD(Exception, __construct)
{
zend_string *message = NULL;
zend_long code = 0;
zval tmp, *object, *previous = NULL;
zend_class_entry *base_ce;
object = ZEND_THIS;
base_ce = i_get_exception_base(Z_OBJ_P(object));
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) {
RETURN_THROWS();
}
if (message) {
ZVAL_STR(&tmp, message);
zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
}
if (code) {
ZVAL_LONG(&tmp, code);
zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
}
if (previous) {
zend_update_property_ex(base_ce, Z_OBJ_P(object), ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
}
}
/* }}} */
C言語的には code
は long long
で定義されている。
typedef int64_t zend_long;
Exceptionが提供しているmethodは getCode
のみ。
Zend/zend_exceptions.c#L441-L452:
/* {{{ Get the exception code */
ZEND_METHOD(Exception, getCode)
{
zval *prop, rv;
ZEND_PARSE_PARAMETERS_NONE();
prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_CODE);
ZVAL_DEREF(prop);
ZVAL_COPY(return_value, prop);
}
/* }}} */
使用例
以下のように取得できる。 プロジェクト内でエラーコードをintegerで統一できているなら使い道がありそう。
const ERROR_CODE = 10;
try {
throw new \Exception(null, ERROR_CODE);
} catch (\Exception $e) {
var_dump($e->getCode());
}
int(10)
PHPUnitでcodeを元にexcepionする関数 TestCase#expectExceptionCode
が生えているのでテスト時に使えそう。
https://github.com/sebastianbergmann/PHPUnit/blob/main/src/Framework/TestCase.php#L430-L433