ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHP, エラー制御演算子(@)でエラー出力を抑えられる。しかし、使うのはやめよう!

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

PHPはエラーなどのログが出そうなところで@演算子を使うと、出力を抑えることができます。でも使ってはいけません。

PHPを使い始めて10年以上経ちますが、1回も使ったことがないし実際コードで見たこともありません。

というか、こういうのがあるのすら忘れてた。

知らないのは非常識か? 使用不可が常識か?

プログラミングでのログ出力は、本来の処理とは関係ないもので暴論を言えばいらないです。じっさいスケジュールが詰まってくると、『そのへんは置いといて動くもの作って!』と言われることもあります。

これを言われると、エンジニアは地獄の入り口が見えるのでやりたくないんですが、置いといたままお役御免なんてこともしばしば。

仕事でプログラムを読むときソースコードのレベルが低いことがよくあります。でもプログラマのレベルが低いとはかぎりません。そのプログラマが納得してないこともあるから。

こういうことは良くあるので、ログ処理が中途半端なことが多々あります。

エラー制御演算子(@)は、意図的にログ出力を抑制するものです。外部要因でしぶしぶじゃなくて、わざと出さないもの。

冒頭で忘れてたというのは、ログをわざと出さないことはしないから。自分の首を絞めるようなもの。

使いみちがあるとすれば...

ログは開発時や保守・メンテのときに力を発揮します。トラブルを素早く対応するには絶対に必要なもの。それを出さないなんてリスクでしか無い。

想像ですが、『ログがユーザーに見えている。処理自体に問題はない。とりあえず消せ!』というとき、一番手っ取り早い方法で使うんでしょう。

ただこれは問題の解決になってないし多用されると本当に困ります。

使ってはいけないと言いましたが使ってもいいです。ただし、あとで必ず外してソースに残さないという前提で。

とりあえず暫定措置で@演算子を使い、根本解決をして終わったら外すという使い方。

エラーを抑制できるのは式だけ

エラー制御演算子の@の使い方はかんたんです。式だけに付けることができます。サンプルコードで見てみましょう。

変数

同じ変数で片方だけに@を付けてログの抑制を確認します。

変数のログの抑制
<?php

$arr[$key];
@$arr[$key];
実行結果
php error-control-operator-variable.php
PHP Notice:  Undefined variable: arr in /home/.../error-control-operator-variable.php on line 3
PHP Notice:  Undefined variable: key in /home/.../error-control-operator-variable.php on line 3
PHP Notice:  Trying to access array offset on value of type null in /home/.../error-control-operator-variable.php on line 3

2行分の通知ログがあるはずですが、4行目は抑制されて出ません。

関数

まずは標準関数につけてみます。

内部関数のログの抑制
<?php

@file('test.txt');
file('test.txt')
実行結果
php error-control-operator-function-1.php
PHP Warning:  file(test.txt): failed to open stream: No such file or directory in /home/.../error-control-operator-function-1.php on line 4

今度は自作関数で実行してみます。ログレベルをエラーに上げて見るために、まずは@を使わないところから。

自作関数のエラーログの表示
<?php

function test($msg)
{
	trigger_error('test() error', E_USER_ERROR);
}

test('first');
echo '----- end -----';
実行結果
php error-control-operator-function-2.php
PHP Fatal error:  test() error in /home/.../error-control-operator-function-2.php on line 5

これに@を使ってみましょう。

エラーログの抑制
<?php

function test($msg)
{
        trigger_error('test() error', E_USER_ERROR);
}

@test('first');
echo '----- end -----';
実行結果
php error-control-operator-function-2.php

ね? ヤバいでしょ? 致命的なエラーになって処理が途中で終わっているのに、何が起きているのかさっぱり分かりません。

この仕様はPHP8では修正されています。PHP8では、Fatal Errorは@を付けてもログを出すようになっています。

今度は未定義の関数で実行してみます。

未定義関数の実行
<?php

@test('first')
実行結果
php error-control-operator-function-3.php
PHP Fatal error:  Uncaught Error: Call to undefined function test() in /home/.../error-control-operator-function-3.php:3
Stack trace:
#0 {main}
  thrown in /home/.../error-control-operator-function-3.php on line 3

未定義の関数はログが出ました。理由は正確には例外エラーだから。Exceptionを継承した例外クラスがスローするログは@を付けても出力されます。

(PHP8より前でも。このサンプルはPHP7で実行。)

クラス

クラスオブジェクトで見てみましょう。クラスではエラーは例外を使うのがスタンダードなので、基本的には@演算子は効きません。

クラスの例外エラー
<?php

class Test
{
	function __construct($msg)
	{
		throw new Exception('constcut failed');
	}
}

@(new Test('test1'));

インスタンス生成ではnewの前に@を付けます。クラス名の前につけるとシンタックスエラーになるので注意。

実行結果
php error-control-operator-class-1.php
PHP Fatal error:  Uncaught Exception: constcut failed in /home/.../error-control-operator-class-1.php:7
Stack trace:
#0 /home/.../error-control-operator-class-1.php(11): Test->__construct()
#1 {main}
  thrown in /home/.../error-control-operator-class-1.php on line 7

今度はクラスの中で、ログ出力をしてみます。エラーログを使う人はいないので(例外を使う。)、警告を出してみます。

クラス内のログ出力
<?php

class Test
{
	function __construct($msg)
	{
		trigger_error('test() parameter failed [' . $msg . ']', E_USER_WARNING)
	}
}

new Test('test1');
echo 'process continue...' . PHP_EOL
実行結果
php error-control-operator-class-2.php
PHP Warning:  test() parameter failed [test1] in /home/.../error-control-operator-class-2.php on line 7
process continue...

警告なので処理は続行します。@演算子を付けてみます。

クラス内のログ抑制
<?php

// 省略...

@new Test('test1');
echo 'process continue...' . PHP_EOL
実行結果
php error-control-operator-class-2.php
process continue...

ログ抑制はできましたが、何が起きているのかさっぱり分かりません。

ダイレクトにログ抑制

最後に、trigger_error()に直接@を付けます。もちろんこれでも抑制ができます。

ダイレクトでログ抑制
<?php

trigger_error('1', E_USER_DEPRECATED);
@trigger_error('2', E_USER_DEPRECATED);

trigger_error('1', E_USER_NOTICE);
@trigger_error('2', E_USER_NOTICE);

trigger_error('1', E_USER_WARNING);
@trigger_error('2', E_USER_WARNING);

@trigger_error('1', E_USER_ERROR)
実行結果
php error-control-operator-trigger-error.php
PHP Deprecated:  1 in /home/.../error-control-operator-trigger-error.php on line 3
PHP Notice:  1 in /home/.../error-control-operator-trigger-error.php on line 6
PHP Warning:  1 in /home/.../error-control-operator-trigger-error.php on line 9

@演算子がついた '2' だけが抑制されているのが分かります。

前の投稿
PHP, 文字列オフセットの特長。サンプルコードで他言語との比較。
PHP, urlencode() は rawurlencode() に変えるべき?
次の投稿
コメントを残す

*