PHP 7.2.0から未定義定数を使用した配列アクセス ($foo[bar]
) がE_WARNING
を出力
導入
PHPで配列要素へのアクセスとして,以下の記法が存在していた。
$foo[bar]
しかし,この記法がどうやらPHPのバージョンによって,エラー出力レベルが変わるようで,新しいPHPだと問題になるようだ。
気になったので,この記法について調べた。
原因
この$foo[bar]
の記法については,PHP公式マニュアルで解説されている。
PHPの変数は$の前置が必須であり,リテラル値以外で$
が前置されていない場合,定数か関数とみなされる。そのため,$foo[bar]
のbar
は丸括弧が欠落しているため,定数とみなされる。
ここで,bar
が未定義の場合,配列の添字が空となり,エラーが予想される。しかし,PHPでは未定義の定数は定数名の文字列 ('bar'
)とみなされる。
そのため,$foo[bar]
の記法が成立していた。ただし,$foo[bar]
で排列要素にアクセスする場合,PHP 7.2.0未満まではE_NOTICE
レベルのエラーが出力されていた。
これが,PHP 7.2.0からエラーレベルがE_WARNING
に格上げとなった。このことは,上記の他にPHPの7.2での変更点としても明記されている。
PHP 7.2.0以上でこのエラーを抑制したい場合,以下のように既定のエラーレベルに加えて,E_WARNING
のエラーをphp.iniのerror_reporting
プロパティやerror_reporting
関数で設定すればいい。
<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED & ~E_WARNING);
$foo = array("bar" => "bar");
echo $foo[bar] . "\n";
ただし,前述のPHP 7.2.0での変更点の文書で,PHP 8.0.0からはエラー例外を出すことが予告されている。
したがって,未定義定数を使った$foo[bar]
の記法はやめ,素直にリテラル文字列を使った$foo['bar']
や$foo["bar"]
の記法を採用すべきだろう。
再現
この問題を再現・検証するコードを以下に掲載する。GitHubにも掲載している。
<?php
## \file array-access-with-unquoted-strings.php
## \author SENOO, Ken
## \copyright CC0
## \date Created date: 2019-07-13
## \sa https://senooken.jp/post/2019/07/13/
## \brief `$foo[bar]` の記法によるエラー出力の違いを記す。
##
## `$foo[bar]` の記法 (未定義定数barの使用) はPHP 7.2.0未満では,E_NOTICEのエラーが出力され,PHP 7.2.0以上ではE_WARNINGのエラーが出力される。
##
## E_WARNINGは既定のエラーレベルに存在するため,今まで問題なかったPHPコードが,PHPのバージョンアップにより,問題を出すようになった。
$foo = array("bar" => "bar");
echo $foo["bar"] . "\n";
echo $foo[bar] . "\n";
## PHP 7.2.0以上の場合,既定のエラーレベルに存在するE_WARNINGにより,ここで以下のエラーが出力される。
##
## ```
## Warning: Use of undefined constant bar - assumed 'bar' in /home/senooken/project/example/PHP/array-access-without-quotation.php on line 16
## ```
error_reporting(E_NOTICE);
echo $foo[bar] . "\n";
## PHP 7.2.0未満の場合,E_NOTICEの有効により,ここで以下のエラーが出力される。
##
## ```
## Notice: Use of undefined constant bar - assumed 'bar' in /home/senooken/project/example/PHP/array-access-without-quotation.php on line 24
## ```
## 以下のようにE_WARNINGをオフにすれば,PHP 7.2.0以上で `$foo[bar]` によるエラー出力を抑制できる。
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED & ~E_WARNING);
echo $foo[bar] . "\n";
## ただし,PHP 8.0.0以上では `$foo[bar]` の記法はエラー扱いになることが予告されているので,この対応は悪い。
##
## 素直に,`$foo[bar]` を `$foo['bar']` のように,配列添字を一重引用符または二重引用符で囲んだリテラル値にすべきだろう。
結論
未定義定数を使用した配列要素へのアクセス ($foo[bar]
) によるエラー出力の違いを検証した。
PHPは勉強を初めたばかりで,今回のような挙動がなぜ発生するのか,知らなかった。疑問に思い調べたことで,PHPの未定義定数の使用という原因がわかった。
疑問を解消できて勉強になった。PHPはいろんなところで使われているので,バージョン間の違いが問題になりやすい。今後も注意したい。