お前は PHP 7 における Fatal Error / Catchable Fatal Error / Error / ErrorException / Exception の違いを言えるか?

More than 1 year has passed since last update.


導入

煽りタイトルすいません.PHP 7 のエラーや標準例外について,違いを整理し,使い分けを考察する記事です.

【引用】 PHP 7.0.0α2 の例外の例外の継承関係を可視化してみた by @ngyuki

7e7426e0-d147-1443-980b-3a9e5ae1e68f.png


すべてを捕捉対象にする Throwable

Throwable は, PHP 7 の throw 文でスロー可能なあらゆるオブジェクトが実装する基底インターフェイスです. Error および Exception はこれを実装しています.但し,PHPコードとして書かれるクラスが Throwable インターフェイスを直接実装することはできません.

とりあえず catch 句に Throwable と書いておけば,そのブロック内でスローされた ErrorException を捕捉できることが保証されます.

try {

...
} catch (\Throwable $e) {
...
}

但し, Error を捕捉する必要性があるのは,「フレームワークを自作していて,エラー時にもHTMLレンダリングを可能な限り行いたい」など,極めて限定的な場合です.もしリソースの解放などを確実に行いたい場合には finally 句を使うのが正解です.



try {

...
} catch (\Throwable $e) {
unlink('/tmp/tmp.txt');
throw $e;
}



try {

...
} finally {
unlink('/tmp/tmp.txt');
}


エラー / Exception / Error / ErrorException

以上4点の違いや使い分けについて言及します.


旧来のエラー

【引用】 $_GET, $_POSTなどを受け取る際の処理


PHPには主に以下のようなエラーがあります. (これで全てではありません)


E_PARSE (別名: Parse Error, Syntax Error, 文法エラー)

コードが文法的に誤っているときに発生します.一切の処理を行いません.


E_ERROR (別名: Fatal Error, 致命的なエラー)

処理を継続することが不可能になってしまった場合に発生します.発生したところで処理を停止します.これが発生するリスクを持つコードを書いてはいけません.


E_WARNING (別名: Warning, 警告)

処理を継続することは可能ですが,想定外の問題が起こったときに発生します.これが発生するリスクを持つコードは可能な限り書かないでおくべきです.


E_NOTICE (別名: Notice, 通知)

処理を継続することは可能ですが,想定内の問題が起こったときに発生します.これは手を抜いて無視する人と丁寧に対応する人に二分されますが,対応の仕方を知らないまま手抜きをするようなプログラマになってはならないと私は考えるので,ここでは徹底的に対応することにします.


このようなエラーは,PHP処理系内部で発生します.困ったことに,後述する特殊な変換処理を設定しないかぎりは,catch 句で捕捉することができません.「旧来のエラー」は Throwable ではありません.本来ならば全てのエラーは Throwable のもとに体系化されるべきなのですが,これは例外が実装されていなかった時代の名残です.

PHP処理系が持つ標準関数との互換性を強く意識したPHPコードでは,「旧来のエラー」を trigger_error 関数を用いてPHPレベルで能動的に発生させることもあります.


Exception

ErrorThrowable が実装される前の PHP 5 時代には, Throwable の代わりにすべての頂点にいたクラスです. Throwable の実装には ErrorException の2種類がありますが,能動的にスローする際には,普通のPHPコードとして書かれるものはすべて Exception あるいはその継承クラスを使うべきです.


Error

PHP 7 から新設されたクラスです. Error というクラス名になっていますが,「旧来のエラー」とは取り扱いが全く異なるものです. Exception とは対極に, PHP処理系内部あるいはPHP処理系が持つ標準関数との互換性を強く意識したPHPコードで用いられます. PHP 7 以降は trigger_error 関数との使い分けに悩む気もしますが, PHP 5 時代の実装のバックポートには trigger_error 関数が, PHP 7 時代の実装のバックポートには Error が使われるでしょう.


ErrorException

set_error_handler 関数と併用して,先述の「特殊な変換処理」で変換するためだけに存在するクラスです.非常に名前がややこしいですが, ErrorException はあくまで Exception の一部であって, PHP 7 から新設された Error とは無関係です. ErrorException「旧来のエラーから変換される Exceptionという意味です.

【引用】 set_error_handlerErrorException を組み合わせると幸せになるかも


set_error_handler(function($severity, $message, $file, $line) {

throw new ErrorException($message, 0, $severity, $file, $line);
});

但し,ここで設定したハンドラは Fatal Error を受け取ることができず,どうしてもそれに対処したい場合は register_shutdown_function を使って「最後の悪あがき」をする程度しか方法がありません.

register_shutdown_function(function () {

$error = error_get_last();
if (!$error || !($error['type'] & (E_ERROR | E_PARSE | E_USER_ERROR | E_RECOVERABLE_ERROR))) {
return;
}
/* 最後の悪あがきをする */
});

E_RECOVERABLE_ERROR (別名 Catchable Fatal Error) は ErrorException に変換可能な E_ERROR 相当のもので, set_error_handler での設定が無い場合には E_ERROR と同様の扱いになります.PHP 5.2 から一部の E_ERRORE_RECOVERABLE_ERROR に変更されています.

※ PHP 7 では E_WARNING E_ERROR E_RECOVERABLE_ERROR E_PARSE の一部が Error に変更されています.


要約すると…


set_error_handler なしの場合


  • そのまま続行可能な旧来のエラー
    E_NOTICE E_WARNING E_USER_NOTICE E_USER_WARNING

  • 実行が停止する旧来のエラー
    E_ERROR E_PARSE E_RECOVERABLE_ERROR E_USER_ERROR


  • catch 句で捕捉できるもの
    Error  Exception


set_error_handler ありの場合


  • 実行が停止する旧来のエラー
    E_ERROR E_PARSE E_USER_ERROR


  • catch 句で捕捉できるもの
    Error  Exception
    ( Exception には E_NOTICE E_WARNING E_USER_NOTICE
    E_RECOVERABLE_ERROR 変換後の ErrorException が含まれる)


LogicException / RuntimeException

PHPプログラマ向けに提供されている Exception の継承クラスとして, LogicExceptionRuntimeException があります.いろいろな記事で何回も言われていることですが,以下のような使い分けを行うべきです.



  • LogicException … 自身のコード,あるいはそれを利用している第三者のコードにバグがあることを示す例外.


  • RuntimeException … 正しく取り扱っていても起こりうる例外.

以下では,これらを継承しているクラスの使い分けについて言及します.


BadFunctionCallException / BadMethodCallException

これは説明するほどでもないですね.

クラス名
継承元
利用シーン

BadFunctionCallException
LogicException
関数が未実装である場合,
あるいは内部状態的に実行してはいけないタイミングで実行された場合の例外.

BadMethodCallException
LogicException
メソッドが未実装である場合,
あるいは内部状態的に実行してはいけないタイミングで実行された場合の例外.


例: シリアライズを防ぐ

class Klass

{
public function __sleep()
{
throw new \BadMethodCallException('serialization is not supported');
}
}

serialize(new Klass); // BadMethodCallException



OverflowException / UnderflowException

マニュアルによれば,コンテナの「オーバーフロー」「アンダーフロー」にそのまま対応するようです.数値計算のオーバーフローがこれに当てはまるかは…どうだろう?

クラス名
継承元
利用シーン

OverflowException
RuntimeException
コンテナのオーバーフロー時の例外.

UnderflowException
RuntimeException
コンテナのアンダーフロー時の例外.


例: スタックの実装例

class Stack

{
private $elements = [];
private $size;

public function __construct(int $size)
{
if ($size < 1) {
throw new \LengthException("\$size must be positive integer, $size given");
}
$this->size = $size;
}

public function push($value)
{
if (count($elements) >= $size) {
throw new \OverflowException('container is full');
}
$this->elements[] = $value;
}

public function pop()
{
if (empty($this->elements)) {
throw new \UnderflowException('container is empty');
}
return array_pop($this->elements);
}
}



DomainException / InvalidArgumentException / LengthException / OutOfRangeException / OutOfBoundsException / RangeException / UnexpectedValueException

さぁ,見るからにここが一番混沌としています.正直なところ,今から書く説明があっているかどうかすら怪しいです…

LogicExceptionRuntimeException の分類ではなく,例外の内容で分類することにします.


引数や返り値のバリデーションを手広く行うもの

クラス名
継承元
利用シーン

DomainException
LogicException
型は合っているが,想定している
いくつかの取りうる値のどれにも該当しなかった場合の例外.
自分を含め,InvalidArgumentExceptionと一緒くたに
されている気がするけど,もうちょっと使ってあげよう.

RangeException
RuntimeException
型は合っているが,想定している
いくつかの取りうる値のどれにも該当しなかった場合の例外.
DomainExceptionの実行時版.

InvalidArgumentException
LogicException
引数の型が間違っている場合の例外.
スカラータイプヒントおよびTypeError
PHP 7 から導入されたので,今後出番は減っていきそう…

UnexpectedValueException
RuntimeException
返り値の型が想定外であった場合の例外.
引数はコンパイル時エラーでだいたい検出可能,
返り値は実行時でなければ検出できない
…というスタンスでInvalidArgumentExceptionと対になるのだろうか?


コンテナへのアクセスのバリデーションを行うもの

クラス名
継承元
利用シーン

OutOfRangeException
LogicException
固定長であるコンテナのオフセットを無視したアクセスがあった場合の例外.
専らSplFixedArray,あるいはそれを踏襲した実装のために存在するようなもの.

OutOfBoundsException
RuntimeException
可変長であるコンテナのオフセット,
またはインデックスを無視したアクセスがあった場合の例外.
マニュアルによるとDomainExceptionの実行時版であるらしいが,
個人的にはOutOfRangeExceptionの実行時版のように思える.


分類しづらいもの

クラス名
継承元
利用シーン

LengthException
LogicException
専ら「長さ」「大きさ」を表す自然数を
バリデーションしたいときに使いそう.


おまけ: バージョン別・エラーや例外の具体例

PHP 5.0 ~ 5.1 の検証は省略し,手元にある 5.5.34 および 7.0.9 で検証することにします.


マークダウン自動生成コード

<?php

function test($version, $code, $strict = false)
{
$trapped_code = ($strict ? 'declare(strict_types=1);' : '') . '
function preg_grep_keys($pattern, $input, $flags = 0) {
return array_intersect_key(
$input,
array_flip(preg_grep($pattern, array_keys($input), $flags))
);
}
set_error_handler(function ($errno, $errstr) use (&$cancel) {
$cancel = true;
$consts = array_flip(preg_grep_keys("/\AE_/", get_defined_constants()));
echo json_encode([
"type" => "`{$consts[$errno]}`",
"message" => $errstr,
]);
exit;
});
register_shutdown_function(function () use (&$cancel) {
if ($cancel || !$e = error_get_last()) return;
$consts = array_flip(preg_grep_keys("/\AE_/", get_defined_constants()));
echo json_encode([
"type" => "`{$consts[$e["type"]]}`",
"message" => $e["message"],
]);
});
try {
'
. $code . '
} catch (\Exception $e) {
$cancel = true;
echo json_encode([
"type" => "[`" . get_class($e) ."`]",
"message" => $e->getMessage(),
]);
} catch (\Throwable $e) {
$cancel = true;
echo json_encode([
"type" => "[`" . get_class($e) ."`]",
"message" => $e->getMessage(),
]);
}
'
;
$error = json_decode(shell_exec(implode(' ', [
$version < 7 ? '/usr/bin/php' : '/usr/local/bin/php',
'-d error_reporting=-1',
'-d display_errors=0',
'-d log_errors=0',
'-r ' . escapeshellarg($trapped_code),
])));
return $error;
}

function escape_ascii($str)
{
return preg_replace_callback('/[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]/', function ($m) {
return '&#' . ord($m[0]) . ';';
}, $str);
}

function build(array $items)
{
$tables = [
'|No.|概要|PHP 5.5.34|PHP 7.0.9| PHP 7.0.9 (strict)|',
'|:--|:--|:--|:--|:--|',
];
$codes = [];
$i = 0;
foreach ($items as $name => $code) {
$code = trim($code);
$err5 = test(5, $code);
$err7 = test(7, $code);
$err7s = test(7, $code, true);
$tables[] = sprintf('|%s|%s|%s|%s|%s|',
++$i,
$name,
$err5->type ?? '',
$err7->type ?? '',
$err7s->type ?? ''
);
$codes[] = implode("\n", [
'```php:' . escape_ascii("No.$i $name"),
$code,
'/*',
'PHP 5.5.34 : ' . ($err5->message ?? ''),
'PHP 7.0.9 : ' . ($err7->message ?? ''),
'PHP 7.0.9 (strict): ' . ($err7s->message ?? ''),
'*/',
'```'
]);
}
return implode("\n", $tables) . "\n\n" . implode("\n\n", $codes) . "\n";
}

echo build([

'未定義の変数の評価'
=> '
$undefined . "";
'
,

'未定義のグローバル定数の評価'
=> '
UNDEFINED . "";
'
,

'未定義の配列オフセットの評価'
=> '
$ary = [];
$ary[0] . "";
'
,

'未定義の連想配列インデックスの評価'
=> '
$asc = [];
$asc["undefined"] . "";
'
,

'未定義のインスタンスプロパティの評価'
=> '
$obj = new stdClass;
$obj->undefined . "";
'
,

'未定義の静的プロパティの評価'
=> '
$obj = new stdClass;
$obj::$undefined . "";
'
,

'未定義のクラス定数の評価'
=> '
$obj = new stdClass;
$obj::UNDEFINED . "";
'
,

'クラス経由でのインスタンスプロパティへのアクセス'
=> '
class Klass
{
public $prop;
}
Klass::$prop;
'
,

'アクセス権限のないプロパティへのアクセス'
=> '
class Klass
{
private static $prop;
}
Klass::$prop;
'
,

'ゼロ除算'
=> '
1 / 0;
'
,

'ゼロ剰余算'
=> '
1 % 0;
'
,

'マイナスのビットシフト'
=> '
1 << -1;
'
,

'配列と文字列の結合' => '
$ary = [];
$ary . ""; // PHP 7 のコンパイル時エラー回避
'
,

'配列変数と整数の加算' => '
$ary = [];
$ary + 1; // PHP 7 のコンパイル時エラー回避
'
,

'配列リテラルと整数の加算' => '
eval("[] + 1;"); // PHP 7 のコンパイル時エラー回避
'
,

'配列のオフセットの型間違い' =>'
$ary = [];
$ary[[]] . "";
'
,

'__toString()未実装時の文字列キャスト' =>'
$obj = new stdClass;
(string)$obj;
'
,

'__toString()の中でスローされる例外' =>'
class Klass
{
public function __toString()
{
throw new \Exception;
}
}
$obj = new Klass;
(string)$obj;
'
,

'__clone()の直接実行' =>'
class Klass
{
public function __clone()
{
return new self;
}
}
$obj = new Klass;
eval("\$obj->__clone();");// PHP 5 のコンパイル時エラー回避
'
,

'ArrayAccess未実装時の配列形式アクセス' =>'
$obj = new stdClass;
$obj[0] = 1;
'
,

'ユーザ定義関数のタイプヒンティングの無視' => '
function func(stdClass $obj) { }
func(1);
'
,

'ユーザ定義関数の引数不足' => '
function func($a) { }
func();
'
,

'組み込み関数のタイプ指定無視' => '
strlen([]);
'
,

'組み込み関数の引数不足' => '
strlen();
'
,

'組み込み関数の引数余剰' => '
strlen("", "");
'
,

'アサーションの失敗 (assert.exception=0)' => '
assert(false);
'
,

'アサーションの失敗 (assert.exception=1)' => '
ini_set("assert.exception", "1");
assert(false);
'
,

'foreachの型間違い' => '
$num = 1;
foreach ($num as $k => $v);
'
,

]);


No.
概要
PHP 5.5.34
PHP 7.0.9
PHP 7.0.9 (strict)

1
未定義の変数の評価
E_NOTICE
E_NOTICE
E_NOTICE

2
未定義のグローバル定数の評価
E_NOTICE
E_NOTICE
E_NOTICE

3
未定義の配列オフセットの評価
E_NOTICE
E_NOTICE
E_NOTICE

4
未定義の連想配列インデックスの評価
E_NOTICE
E_NOTICE
E_NOTICE

5
未定義のインスタンスプロパティの評価
E_NOTICE
E_NOTICE
E_NOTICE

6
未定義の静的プロパティの評価
E_ERROR
Error
Error

7
未定義のクラス定数の評価
E_ERROR
Error
Error

8
クラス経由でのインスタンスプロパティへのアクセス
E_ERROR
Error
Error

9
アクセス権限のないプロパティへのアクセス
E_ERROR
Error
Error

10
ゼロ除算
E_WARNING
E_WARNING
E_WARNING

11
ゼロ剰余算
E_WARNING
DivisionByZeroError
DivisionByZeroError

12
マイナスのビットシフト

ArithmeticError
ArithmeticError

13
配列と文字列の結合
E_NOTICE
E_NOTICE
E_NOTICE

14
配列変数と整数の加算
E_ERROR
Error
Error

15
配列リテラルと整数の加算
E_ERROR
E_ERROR
E_ERROR

16
配列のオフセットの型間違い
E_WARNING
E_WARNING
E_WARNING

17
__toString()未実装時の文字列キャスト
E_RECOVERABLE_ERROR
E_RECOVERABLE_ERROR
E_RECOVERABLE_ERROR

18
__toString()の中でスローされる例外
E_ERROR
E_ERROR
E_ERROR

19
__clone()の直接実行
E_COMPILE_ERROR

20
ArrayAccess未実装時の配列形式アクセス
E_ERROR
Error
Error

21
ユーザ定義関数のタイプヒンティングの無視
E_RECOVERABLE_ERROR
TypeError
TypeError

22
ユーザ定義関数の引数不足
E_WARNING
E_WARNING
E_WARNING

23
組み込み関数のタイプ指定無視
E_WARNING
E_WARNING
TypeError

24
組み込み関数の引数不足
E_WARNING
E_WARNING
TypeError

25
組み込み関数の引数余剰
E_WARNING
E_WARNING
TypeError

26
アサーションの失敗 (assert.exception=0)
E_WARNING
E_WARNING
E_WARNING

27
アサーションの失敗 (assert.exception=1)
E_WARNING
AssertionError
AssertionError

28
foreachの型間違い
E_WARNING
E_WARNING
E_WARNING


No.1 未定義の変数の評価

$undefined . "";

/*
PHP 5.5.34 : Undefined variable: undefined
PHP 7.0.9 : Undefined variable: undefined
PHP 7.0.9 (strict): Undefined variable: undefined
*/



No.2 未定義のグローバル定数の評価

UNDEFINED . "";

/*
PHP 5.5.34 : Use of undefined constant UNDEFINED - assumed 'UNDEFINED'
PHP 7.0.9 : Use of undefined constant UNDEFINED - assumed 'UNDEFINED'
PHP 7.0.9 (strict): Use of undefined constant UNDEFINED - assumed 'UNDEFINED'
*/



No.3 未定義の配列オフセットの評価

$ary = [];

$ary[0] . "";
/*
PHP 5.5.34 : Undefined offset: 0
PHP 7.0.9 : Undefined offset: 0
PHP 7.0.9 (strict): Undefined offset: 0
*/



No.4 未定義の連想配列インデックスの評価

$asc = [];

$asc["undefined"] . "";
/*
PHP 5.5.34 : Undefined index: undefined
PHP 7.0.9 : Undefined index: undefined
PHP 7.0.9 (strict): Undefined index: undefined
*/



No.5 未定義のインスタンスプロパティの評価

$obj = new stdClass;

$obj->undefined . "";
/*
PHP 5.5.34 : Undefined property: stdClass::$undefined
PHP 7.0.9 : Undefined property: stdClass::$undefined
PHP 7.0.9 (strict): Undefined property: stdClass::$undefined
*/



No.6 未定義の静的プロパティの評価

$obj = new stdClass;

$obj::$undefined . "";
/*
PHP 5.5.34 : Access to undeclared static property: stdClass::$undefined
PHP 7.0.9 : Access to undeclared static property: stdClass::$undefined
PHP 7.0.9 (strict): Access to undeclared static property: stdClass::$undefined
*/



No.7 未定義のクラス定数の評価

$obj = new stdClass;

$obj::UNDEFINED . "";
/*
PHP 5.5.34 : Undefined class constant 'UNDEFINED'
PHP 7.0.9 : Undefined class constant 'UNDEFINED'
PHP 7.0.9 (strict): Undefined class constant 'UNDEFINED'
*/



No.8 クラス経由でのインスタンスプロパティへのアクセス

class Klass

{
public $prop;
}
Klass::$prop;
/*
PHP 5.5.34 : Access to undeclared static property: Klass::$prop
PHP 7.0.9 : Access to undeclared static property: Klass::$prop
PHP 7.0.9 (strict): Access to undeclared static property: Klass::$prop
*/



No.9 アクセス権限のないプロパティへのアクセス

class Klass

{
private static $prop;
}
Klass::$prop;
/*
PHP 5.5.34 : Cannot access private property Klass::$prop
PHP 7.0.9 : Cannot access private property Klass::$prop
PHP 7.0.9 (strict): Cannot access private property Klass::$prop
*/



No.10 ゼロ除算

1 / 0;

/*
PHP 5.5.34 : Division by zero
PHP 7.0.9 : Division by zero
PHP 7.0.9 (strict): Division by zero
*/



No.11 ゼロ剰余算

1 % 0;

/*
PHP 5.5.34 : Division by zero
PHP 7.0.9 : Modulo by zero
PHP 7.0.9 (strict): Modulo by zero
*/



No.12 マイナスのビットシフト

1 << -1;

/*
PHP 5.5.34 :
PHP 7.0.9 : Bit shift by negative number
PHP 7.0.9 (strict): Bit shift by negative number
*/



No.13 配列と文字列の結合

$ary = [];

$ary . ""; // PHP 7 のコンパイル時エラー回避
/*
PHP 5.5.34 : Array to string conversion
PHP 7.0.9 : Array to string conversion
PHP 7.0.9 (strict): Array to string conversion
*/



No.14 配列変数と整数の加算

$ary = [];

$ary + 1; // PHP 7 のコンパイル時エラー回避
/*
PHP 5.5.34 : Unsupported operand types
PHP 7.0.9 : Unsupported operand types
PHP 7.0.9 (strict): Unsupported operand types
*/



No.15 配列リテラルと整数の加算

eval("[] + 1;"); // PHP 7 のコンパイル時エラー回避

/*
PHP 5.5.34 : Unsupported operand types
PHP 7.0.9 : Unsupported operand types
PHP 7.0.9 (strict): Unsupported operand types
*/



No.16 配列のオフセットの型間違い

$ary = [];

$ary[[]] . "";
/*
PHP 5.5.34 : Illegal offset type
PHP 7.0.9 : Illegal offset type
PHP 7.0.9 (strict): Illegal offset type
*/



No.17 __toString()未実装時の文字列キャスト

$obj = new stdClass;

(string)$obj;
/*
PHP 5.5.34 : Object of class stdClass could not be converted to string
PHP 7.0.9 : Object of class stdClass could not be converted to string
PHP 7.0.9 (strict): Object of class stdClass could not be converted to string
*/



No.18 __toString()の中でスローされる例外

class Klass

{
public function __toString()
{
throw new \Exception;
}
}
$obj = new Klass;
(string)$obj;
/*
PHP 5.5.34 : Method Klass::__toString() must not throw an exception
PHP 7.0.9 : Method Klass::__toString() must not throw an exception, caught Exception:
PHP 7.0.9 (strict): Method Klass::__toString() must not throw an exception, caught Exception:
*/



No.19 __clone()の直接実行

class Klass

{
public function __clone()
{
return new self;
}
}
$obj = new Klass;
eval("\$obj->__clone();");// PHP 5 のコンパイル時エラー回避
/*
PHP 5.5.34 : Cannot call __clone() method on objects - use 'clone $obj' instead
PHP 7.0.9 :
PHP 7.0.9 (strict):
*/



No.20 ArrayAccess未実装時の配列形式アクセス

$obj = new stdClass;

$obj[0] = 1;
/*
PHP 5.5.34 : Cannot use object of type stdClass as array
PHP 7.0.9 : Cannot use object of type stdClass as array
PHP 7.0.9 (strict): Cannot use object of type stdClass as array
*/



No.21 ユーザ定義関数のタイプヒンティングの無視

function func(stdClass $obj) { }

func(1);
/*
PHP 5.5.34 : Argument 1 passed to func() must be an instance of stdClass, integer given, called in Command line code on line 27 and defined
PHP 7.0.9 : Argument 1 passed to func() must be an instance of stdClass, integer given, called in Command line code on line 27
PHP 7.0.9 (strict): Argument 1 passed to func() must be an instance of stdClass, integer given, called in Command line code on line 27
*/



No.22 ユーザ定義関数の引数不足

function func($a) { }

func();
/*
PHP 5.5.34 : Missing argument 1 for func(), called in Command line code on line 27 and defined
PHP 7.0.9 : Missing argument 1 for func(), called in Command line code on line 27 and defined
PHP 7.0.9 (strict): Missing argument 1 for func(), called in Command line code on line 27 and defined
*/



No.23 組み込み関数のタイプ指定無視

strlen([]);

/*
PHP 5.5.34 : strlen() expects parameter 1 to be string, array given
PHP 7.0.9 : strlen() expects parameter 1 to be string, array given
PHP 7.0.9 (strict): strlen() expects parameter 1 to be string, array given
*/



No.24 組み込み関数の引数不足

strlen();

/*
PHP 5.5.34 : strlen() expects exactly 1 parameter, 0 given
PHP 7.0.9 : strlen() expects exactly 1 parameter, 0 given
PHP 7.0.9 (strict): strlen() expects exactly 1 parameter, 0 given
*/



No.25 組み込み関数の引数余剰

strlen("", "");

/*
PHP 5.5.34 : strlen() expects exactly 1 parameter, 2 given
PHP 7.0.9 : strlen() expects exactly 1 parameter, 2 given
PHP 7.0.9 (strict): strlen() expects exactly 1 parameter, 2 given
*/



No.26 アサーションの失敗 (assert.exception=0)

assert(false);

/*
PHP 5.5.34 : assert(): Assertion failed
PHP 7.0.9 : assert(): assert(false) failed
PHP 7.0.9 (strict): assert(): assert(false) failed
*/



No.27 アサーションの失敗 (assert.exception=1)

ini_set("assert.exception", "1");

assert(false);
/*
PHP 5.5.34 : assert(): Assertion failed
PHP 7.0.9 : assert(false)
PHP 7.0.9 (strict): assert(false)
*/



No.28 foreachの型間違い

$num = 1;

foreach ($num as $k => $v);
/*
PHP 5.5.34 : Invalid argument supplied for foreach()
PHP 7.0.9 : Invalid argument supplied for foreach()
PHP 7.0.9 (strict): Invalid argument supplied for foreach()
*/