正确的方式来处理不可避免的警告
还有就是可以发出警告,由于对错误有可能在正常运行的情况发生的条件,如许多好的旧程序功能:fopen()
,mail()
,oci_connect()
...正确的方式来处理不可避免的警告
-
的most obvious workaround据说是昂贵的,并具有隐藏一切的副作用:
echo @file_get_contents(oops_forgot_dollar);
-
自定义错误处理程序看起来Ø verkill:
private function warningHandler($errno, $errstr, $errfile, $errline/*, array $errcontext*/){ if(error_reporting()===0){ return false; }else{ throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } } // .... try{ set_error_handler('CSVLoader::warningHandler', E_WARNING); $this->fp = fopen($filename, 'r'); restore_error_handler(); $this->readData(); }catch(ErrorException $e){ restore_error_handler(); throw new CSVLoaderException("Could not open file: {$e->getMessage()}"); }
-
又让警告穿过即使在一个正确配置的服务器是烦人:
- 在研究与开发他们在荒郊野外显示并可以打破的东西
- 在生产他们用无用的数据淹没错误日志
建议的做法是什么? PHP专家如何处理它?
error_log里是不是无用数据
我觉得它通常是很容易的继续,如果有一个小时的cron作业的最上面的那的error_log文件的人的电子邮件内容.....
不久,您将在适当的检查中添加代码库和排序的问题。
我很欣赏你花时间撰写了答案,但我不确定你是否真的理解我的问题。想象一下,你维护一个库来发送电子邮件。当传出SMTP连接失败时,您的库会引发一个很好的'FooMailer \ TransportException'。它触发(并记录!)一个额外的不可捕捉的'E_WARNING'有什么意义?终端用户是否会觉得更合理,只是将邮件标记为未发送到他们的新闻通讯数据库中? –
最终用户永远不会找到error_log或类似的帮助很多的消息 - 他们需要一个更有帮助的消息(“对不起,发生了一些非常糟糕的事情”,“您没有正确填写所有表单域)。” 如何检测你的错误是由你自己决定的,例外情况与检查返回值或其他值一样。 很显然,在设计你的应用程序/系统时,你知道某些东西可能会失败(发送简报到许多地址,并且可以在以后的日期重试),而其他事情是例外事件 - (例如数据库服务器已死) –
我做了一些流行的PHP框架和流行的Packagist包间快速肮脏的倾斜不科学的调查,发现这一点:
- 错误抑制操作是合理的流行(笨,•奈特,斯威夫特梅勒,Yii的.. )。
- 其他项目使用
set_error_handler()
投掷ErrorException
或其他一些异常(Zend,Symfony,Laravel,PHPUnit,Psy ...)。大多数简单地使用项目范围的错误处理程序,一些(PHPMailer)在设置/恢复调用中包装特定的操作。 - 一些其他项目显然只是不在乎(PHPExcel)。
我想说的是:
- 如果你已经有了一个自定义的错误处理程序,它可能更好地利用它。
- 否则,错误控制操作符可能会很好(但在开发该代码段时暂时删除它可能是一个好主意)。无论如何,所谓的不良表现doesn't seem to be a big deal *,尤其是,如果你正在做一个“慢”操作,比如打开一个数据库连接,套接字或文件。
- 作为辩论,它可能在标签与空格相同的区域。
(*)我发现,比较@
与isset()
并确定@
很慢无尽的基准。真正发生的是isset()
非常快 - 实际上是much faster that not using either。
最后但并非最不重要的,因为性能的问题,我将分享我的第一家酿造基准一次更快速和肮脏的一个,没有一个适当的基准框架。请注意,我只是想试探迄今最坏的情况(所有的函数调用发出警示):在我的Windows 7盒
<?php
error_reporting(-1);
ini_set('display_errors', false);
ini_set('log_errors', false);
define('ITERATIONS', 10000);
function warning_handler($errno, $errstr, $errfile, $errline/*, array $errcontext*/){
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
echo sprintf('Running %s iterations on PHP/%s...' . PHP_EOL, number_format(ITERATIONS), phpversion());
$t0 = microtime(true);
for($i=0; $i<ITERATIONS; $i++){
fopen("FooA $i", 'r');
}
echo sprintf('Raw: % 6.3fs' . PHP_EOL, microtime(true) - $t0);
$t0 = microtime(true);
for($i=0; $i<ITERATIONS; $i++){
@fopen("FooB $i", 'r');
}
echo sprintf('@: % 6.3fs' . PHP_EOL, microtime(true) - $t0);
$t0 = microtime(true);
for($i=0; $i<ITERATIONS; $i++){
set_error_handler('warning_handler', E_WARNING);
try{
fopen("FooC $i", 'r');
restore_error_handler();
}catch(ErrorException $e){
restore_error_handler();
}
}
echo sprintf('Local set_error_handler(): % 6.3fs' . PHP_EOL, microtime(true) - $t0);
$t0 = microtime(true);
set_error_handler('warning_handler', E_WARNING);
for($i=0; $i<ITERATIONS; $i++){
try{
fopen("FooD $i", 'r');
}catch(ErrorException $e){
}
}
restore_error_handler();
echo sprintf('General set_error_handler(): % 6.3fs' . PHP_EOL, microtime(true) - $t0);
结果(86 PHP版本):
Running 10,000 iterations on PHP/5.3.28...
Raw: 1.388s
@: 1.232s
Local set_error_handler(): 1.638s
General set_error_handler(): 1.497s
Running 10,000 iterations on PHP/5.4.24...
Raw: 1.170s
@: 1.185s
Local set_error_handler(): 1.357s
General set_error_handler(): 1.326s
Running 10,000 iterations on PHP/5.5.22...
Raw: 1.185s
@: 1.341s
Local set_error_handler(): 4.960s
General set_error_handler(): 4.570s
Running 10,000 iterations on PHP/5.6.10...
Raw: 1.139s
@: 1.139s
Local set_error_handler(): 1.263s
General set_error_handler(): 1.232s
Running 10,000 iterations on PHP/7.0.0beta1...
Raw: 1.232s
@: 1.279s
Local set_error_handler(): 1.669s
General set_error_handler(): 1.669s
通常由CH在进行函数调用之前设置正确的条件,即用'file_get_contents',在调用之前做一个'is_readable'调用,这不会引发错误,但会让您深入了解'file_get_contents'是否会出错 – naththedeveloper
@ɴᴀᴛʜ - 我不是很确信。您如何事先知道数据库服务器是否会接受连接?即使你变得固执并用'fsockopen()'模拟一个''''你会需要*更多*以前的检查以防''fsockopen()'也触发警告。这种方法也意味着选择不使用像'file_get_contents()'这样的设备:任何读取文件的代码都需要大量的样板文件。 –