1、抛出Deprecated提示,虽然不影响运行,但是官方 不推荐使用 ,如 有些老版本的函数,需要用官方推荐的代替函数替换
2、Parse error、Fatal Error这种高级别错误会终止程序运行
3、生产线上错误日志控制
线上的错误信息肯定是要记录的,error_reporting(0)这样会导致所有的错误信息不会记录,应该:error_reporting = E_ALL ,只要display_errors = Off,错误信息就不会再页面上显示,因为display_errors的优先级别更高。
特别要注意的是:
如果php.ini中log_errors= On,据官方的说法,那么必须指定error_log文件,如果没指定或者指定的文件没有权限写入,那么照样会输出到正常的输出渠道,那么也就使得display_errors 这个指定的Off失效,错误信息还是打印了出来。
总结下,在生产环境中错误信息记录错误日志:
<?php
error_reporting(E_ALL);
ini_set('display_errors',0);
ini_set('log_errors',1);
ini_set('error_log','/hotdata/php_log/'.date('Y-m-d').'_error_log.txt');
产生一个用户级别的 error/warning/notice 信息
trigger_error(‘错误提示内容’, E_USER 系列常量);
错误级别:
E_USER_NOTICE 继续执行
E_USER_WARNING 继续执行
E_USER_ERROR 程序不再执行
<?php
error_reporting(E_ALL);
// ini_set('display_errors',0);
ini_set('log_errors',1);
ini_set('error_log','H:\\wamp\\PHPnow-1.5.6.1428396605\\htdocs\\'.date('Y-m-d').'_log.txt');
$a = 1;
$b = '2';
if(is_numeric($a) && is_numeric($b))
{
// trigger_error('必须传递数字类型的变量',E_USER_NOTICE);
// trigger_error('必须传递数字类型的变量',E_USER_WARNING);
trigger_error('必须传递数字类型的变量',E_USER_ERROR);
}else{
echo $a + $b;
}
echo '程序继续运行';
<?php
error_reporting(E_ALL);
ini_set('display_errors',-1);
ini_set('log_errors',1);
ini_set('error_log','syslog');
// ini_set('ignore_user_abort()ore_repeated_errors','on');//忽略重复的信息
// ini_set('ignore_repeated_source','on');//忽略消息的来源
openlog('test', LOG_PID, 'this is test');
syslog(LOG_ERR, "This is a test: " . memory_get_usage(true));
closelog();
PHP里有一套错误处理机制,可以使用set_error_handler接管PHP错误的处理,可以实现自定义的错误处理器
<?php
/** * 自定义错误处理器 */
class MyErrorHandler
{
public $message = '';
public $filename = '';
public $line = 0;
public $vars = array();
public $_noticelog = 'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\run_log\\';
public function __construct($message,$filename,$line,$vars)
{
$this -> message = $message;
$this -> filename = $filename;
$this-> line = $line;
$this -> vars = $vars;
}
public static function deal($errorno,$errmsg,$filename,$line,$vars)
{
$self = new self($errmsg,$filename,$line,$vars);
switch ($errorno) {
case E_USER_ERROR:
return $self -> dealError();
break;
case E_USER_WARNING:
return $self -> dealWarning();
break;
case E_WARNING:
return $self -> dealWarning();
break;
case E_NOTICE:
return $self -> dealNotice();
break;
case E_USER_NOTICE:
return $self -> dealNotice();
break;
default:
return False;
break;
}
}
/** * 处理错误信息 */
public function dealError()
{
ob_start();//开启内存缓冲
debug_print_backtrace();
$backtrace = ob_get_flush();//得到输出缓冲的内容
$errormsg = <<<EOF
出现了致命的错误,如下:
产生错误的文件:{$this->filename}
产生错误的信息:{$this->message}
产生错误的行号:{$this->line}
追踪信息:{$backtrace}
EOF;
error_log($errormsg,1,'[email protected]');
exit(1);
}
/** * 处理警告信息 */
public function dealWarning()
{
$errormsg = <<<EOF
出现了警告的错误,如下:
产生警告的文件:{$this->filename}
产生警告的信息:{$this ->message}
产生警告的行号:{$this ->line}
EOF;
return error_log($errormsg,1,'[email protected]');
}
/** * 处理通知级别错误,写入日志 */
public function dealNotice()
{
$datetime = date('Y-m-d H:i:s');
$errormsg = <<<EOF
出现了通知的错误,如下:
产生通知的文件:{$this->filename}
产生通知的信息:{$this ->message}
产生通知的行号:{$this ->line}
产生通知的时间:{$datetime}
EOF;
return error_log($errormsg,3,$this->_noticelog.date('Y-m-d').'.txt');
}
}
测试上述代码:
<?php require './MyErrorHandler.php'; error_reporting(-1); set_error_handler(array('MyErrorHandler','deal')); echo $test; settype($var, 'nothistype'); trigger_error('手动抛出致命错误',E_USER_ERROR); echo '没有运行';
1)通过register_shutdown_function()函数,可以让我们设置一个当执行关闭时可以被调用的另一个函数
2)当我们的脚本执行完成或意外死掉导致PHP执行即将关闭时,我们的函数将会调用
使用场景:
1、页面强制被停止
2、程序代码意外终止或超时
<?php class Shutdown { public function endScriptDeal() { if(error_get_last()) { echo "<pre>"; print_r(error_get_last()); echo "</pre>"; } $data = 'this is test'; //输出到文件的路径必须为绝对路径,否则无法写入 file_put_contents('H:\wamp\PHPnow-1.5.6.1428396605\htdocs\run_log\run_error.txt', $data); die('end script'); } } echo 'hello world'; echo md6();//调用一个不存在的函数,将引发Fatal error die;//register_shutdown_function之前有die或exit的情况下,下方代码将不执行;当然die或exit在其之后将可执行 register_shutdown_function(array(new Shutdown(),'endScriptDeal')); // echo md4();
<?php
/* try(){ #code throw new Exception('异常信息'); }catch(Exception $e){ echo $e -> getMessage(); }*/
//==下方代码异常没有抛出,所以未能捕获
$num = 0;
$num2 = 3;
try{
$num = 3/0;
var_dump($num);
}catch(Exception $e){
echo $e -> getMessage();
$num = 12;
}
echo 'continue';
echo $num.'<br/>';
//=======================
//主动抛出异常并捕获
//=======================
try
{
$num1= 2;
$num3= 0;
if($num3 ==0)
{
throw new Exception('0不能被当作除数');
}else{
$res = $num1/$num3;
}
}catch(Exception $e){
echo $e -> getMessage();
$num4 =33;
}
//==============
//没有catch块将报解析错误(语法错误)
//==============
// try
// {
// $num1= 2;
// $num3= 0;
// if($num3 ==0)
// {
// throw new Exception('0不能被当作除数');
// }else{
// $res = $num1/$num3;
// }
// }
//=================
//
<?php
//==============
//PDO内置异常处理,无需抛出即可捕获
//==============
try{
$pdo = new Pdo("mysql:host=localhost;dbname=mysql",'root','333');
var_dump($pdo);
echo 'continue...';
}catch(PDOException $e){
echo $e -> getMessage();
}
echo 'this is test'.'<br/>';
//==============
//Spl内置异常处理,也是不抛出异常也可捕获
//==============
try{
$splObj = new SplFileObject('test.text','r');
echo 'read file..';
}catch(Exception $e){
echo $e ->getMessage();
}
echo 'this is Spl';
异常处理
当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 “catch” 代码块。
如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 “Uncaught Exception” (未捕获异常)的错误消息。
处理处理程序应当包括:
try - 使用异常的函数应该位于 “try” 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。
throw - 这里规定如何触发异常。每一个 “throw” 必须对应至少一个 “catch”
catch - “catch” 代码块会捕获异常,并创建一个包含异常信息的对象
重新抛出异常
有时,当异常被抛出时,您也许希望以不同于标准的方式对它进行处理。可以在一个 “catch” 代码块中再次抛出异常。
脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常。
异常的规则
需要进行异常处理的代码应该放入 try 代码块内,以便捕获潜在的异常。
每个 try 或 throw 代码块必须至少拥有一个对应的 catch 代码块。
使用多个 catch 代码块可以捕获不同种类的异常。
可以在 try 代码块内的 catch 代码块中再次抛出(re-thrown)异常。
简而言之:如果抛出了异常,就必须捕获它。
//=============
//下方写法是错误的
//Fatal error: Uncaught exception 'Exception' with message 'Test2 Error Processing Request'
//=============
// try{
// throw new Exception("Test Error Processing Request");
// }catch(Exception $e){
// echo $e->getMessage();
// throw new Exception("Test2 Error Processing Request");
// }catch(Exception $e){
// echo $e ->getMessage();
// }
//============
//更正如下
//============
try{
throw new Exception("Test Error Processing Request");
}catch(Exception $e){
echo '<br/>'.$e->getMessage().'<br/>';
try{
throw new Exception("Test2 Error Processing Request");
}catch(Exception $e){
echo $e ->getMessage().'<br/>';
}
}
echo 'continue...';
当自定义异常处理类后,在写catch捕获多个异常时,如果基类放上面,则其他子类则无法捕获异常
<?php
//==================
//基类可以捕获所有异常,基类放上面,下面再写子类的异常捕获就没有意义了
//==================
class MyException extends Exception {
}
try{
throw new MyException("Error Processing Request");
}catch( Exception $e){
echo '我是基类';
echo $e -> getMessage();
}catch(MyException $e){
echo '我是自定义子类';
echo $e -> getMessage();
}
自定义异常类
<?php
class FileException extends Exception {
public function getDetails() {
switch ($this->code)
{
case 0:
return '没有提供文件';
break;
case 1:
return '文件不存在';
break;
case 2:
return '不是一个文件';
break;
case 3:
return '文件不可写';
break;
case 4:
return '非法文件的操作模式';
break;
case 5:
return '数据写入失败';
break;
case 6:
return '文件不能被关闭';
break;
default:
return '非法';
break;
}
}
}
class WriteData {
public function __construct($filename = null,$mode = 'w') {
$this -> _message = '文件:'.$filename.'模式:'.$mode;
if(empty($filename))
throw new FileException($this->_message, 0);
if(!file_exists($filename))
throw new FileException($this->_message, 1);
if(!is_file($filename))
throw new FileException($this->_message, 2);
if(!is_writable($filename))
throw new FileException($this->_message, 3);
if(!in_array($mode, array('w','w+','a','a+')))
throw new FileException($this->_message, 4);
$this->_fp = fopen($filename,$mode);
}
public function write($data) {
if(!fwrite($this->_fp, $data.PHP_EOL))
throw new FileException($this->_message, 5);
}
public function close() {
if($this->_fp)
{
if(!fclose($this->_fp))
{
throw new FileException($this->_message, 6);
}
$this->_fp = NULL;
}
}
public function __destruct() {
$this -> close();
}
}
try{
$fp = new WriteData('test.txt','w');
$fp -> write('this is a test');
$fp -> close();
echo '数据写入成功';
}catch(FileException $e){
echo '出现问题了'.$e->getMessage().'详细信息如下:'.$e->getDetails();
}
记录异常信息
<?php
class logException extends Exception {
public function __construct($message='',$code=0) {
parent::__construct($message,$code);
// error_log($this->getTraceAsString(),3,'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\test.txt');
error_log($this->getMessage(),3,'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\test.txt');
}
}
try{
$link = mysql_connect('localhost','root','11');
if(!$link)
throw new logException('数据库连接失败', 1);
}catch(logException $e){
echo $e->getMessage();
}
Exception_observer.php
<?php
/** *给观察者定义的规范 *强制指定类型来自于哪里 */
interface Exception_Observer
{
public function update(observable_exception $e);
}
observable_exception.php
<?php
class observable_exception extends Exception {
public static $_observers = array();
public static function attach(Exception_Observer $observer) {
self::$_observers[] = $observer;
}
public function __construct($message = null, $code = 0) {
parent::__construct($message,$code);
$this -> notify();
}
public function notify() {
foreach (self::$_observers as $observer)
{
$observer -> update($this);
}
}
}
Logging_Exception.php
<?php
/** * */
class Logging_Exception_Observer implements Exception_Observer {
protected $_filename = 'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\logException.log';
function __construct($filename = null) {
if($filename !=null && is_string($filename)){
$this ->_filename = $filename;
}
}
public function update(observable_exception $e) {
$message = '时间:'.date('Y-m-d H:i:s').PHP_EOL;
$message .= '信息:'.$e -> getMessage().PHP_EOL;
$message .= '追踪信息:'.$e -> getTraceAsString().PHP_EOL;
$message .= '文件:'.$e -> getFile().PHP_EOL;
$message .= '行号:'.$e->getLine().PHP_EOL;
error_log($message,3,$this->_filename);//写入日志
}
}
Emailing_Exception.php
<?php
class Emailing_Exception_Observer implements Exception_Observer {
protected $_email = '[email protected]';
public function __construct($email=null) {
if($email != null && filter_var($email,FILTER_VALIDATE_EMAIL))
{
$this -> _email = $email;
}
}
//发送邮件
public function update(observable_exception $e) {
$message = '时间:'.date('Y-m-d H:i:s').PHP_EOL;
$message .= '信息:'.$e -> getMessage().PHP_EOL;
$message .= '追踪信息:'.$e -> getTraceAsString().PHP_EOL;
$message .= '文件:'.$e -> getFile().PHP_EOL;
$message .= '行号:'.$e->getLine().PHP_EOL;
error_log($message,1,$this->_email);//写入日志
}
}
测试代码
testObserver.php
<?php
require_once './Exception_observer.php';
require_once './observable_exception.php';
require_once './Logging_Exception.php';
require './Emailing_Exception.php';
observable_exception::attach(new Logging_Exception_Observer());//观察者1
observable_exception::attach(new Logging_Exception_Observer('test1.log'));//观察者2
observable_exception::attach(new Emailing_Exception_Observer());//观察者3
/** * */
class MyException extends observable_exception {
public function test() {
echo 'This is test';
}
public function test1() {
echo '我是自定义的方法处理这个异常';
}
}
try{
throw new MyException("出现异常了,记录一下");
}catch(MyException $e)
{
echo $e -> getMessage();
echo '<hr/>';
$e -> test();
echo '<hr/>';
$e ->test1();
}
认识set_exception_handler
set_exception_handler.php
<?php
function exceptionHandler_1($e) {
echo '自定义的异常处理器——1<br/>函数名称:'.__FUNCTION__.'<br/>';
echo '异常信息:'.$e->getMessage();
}
function exceptionHandler_2($e) {
echo '自定义的异常处理器——2<br/>函数名称:'.__FUNCTION__.'<br/>';
echo '异常信息:'.$e->getMessage();
}
//直接抛出异常,不接收是会报错的
//Fatal error: Uncaught exception 'Exception' with message 'Error Processing Request'
//throw new Exception("Error Processing Request");
set_exception_handler('exceptionHandler_1');
//当再定义一个异常处理器的时候,上一个会被覆盖
set_exception_handler('exceptionHandler_2');
//恢复到上一个定义过的异常处理器函数
restore_exception_handler();
restore_exception_handler();//Fatal error: Uncaught exception 'Exception' with message
throw new Exception("Error Processing Request");
自定义异常处理器
ExceptionHandler.class.php
<?php
class ExceptionHandler {
protected $_exception;
protected $_logFile = 'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ExceptionHandler.log';
public function __construct(Exception $e) {echo 00;
$this ->_exception = $e;
}
public static function handle(Exception $e) {
$self = new self($e);
$self ->log();
echo $self;
}
/** * 重写Exception的__toString()方法 */
public function __toString() {
$message = <<<EOF <!DOCTYPE html> <html> <head> <title>出现异常了</title> <h1>出现异常了</h1> <a href='mailto:[email protected]'>联系管理员[email protected]</a> </head> <body> </body> </html> EOF;
return $message;
}
public function log() { echo 11;
error_log($this->_exception -> getMessage().PHP_EOL,3,$this->_logFile);
}
}
set_exception_handler(array('ExceptionHandler','handle'));
throw new Exception('this is a test.....');//该信息会被捕获
try{
throw new Exception('this is a test');
} catch (Exception $e){
echo $e ->getMessage();//该信息不会被捕获
}
认识ErrorException
ErrorException.php
<?php
function exception_error_handler($errno,$errstr,$errfile,$errline) {
throw new ErrorException($errstr,0,$errno,$errfile,$errline);
}
set_error_handler('exception_error_handler');
try {
echo gettype();
} catch (Exception $exc) {
echo $exc->getMessage();
}
ErrorToException.php
<?php
//======================================
//下方代码注释后运行结果
//Notice: Undefined variable: test in H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ErrorToException.php on line 16
//Warning: Wrong parameter count for gettype() in H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ErrorToException.php on line 17
//Warning: test in H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ErrorToException.php on line 18
//=======================================
//======下方代码运行结果=================
//Notice: Undefined variable: test in H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ErrorToException.php on line 24
//Wrong parameter count for gettype()
//=======================================
class ErrorToException extends Exception {
public static function handle($errno,$errstr) {
throw new self($errstr,$errno);
}
}
set_error_handler(array('ErrorToException','handle'));
set_error_handler(array('ErrorToException','handle'),E_USER_WARNING|E_WARNING);
//echo $test;
//==================================================
//======测试代码=======
try{
echo $test;
gettype();
trigger_error('test',E_USER_WARNING);
} catch (Exception $e){
echo $e->getMessage();
}
ExceptionRedirct.php
<?php
class ExceptionRedirctHandler {
public $redirct = '404.html';
protected $_exception;
protected $_logFile = 'H:\wamp\PHPnow-1.5.6.1428396605\htdocs\ExceptionRedirctHandler.log';
/** * 获得异常对象 * @param Exception $e */
public function __construct(Exception $e) {
$this->_exception = $e;
}
/** * 接收一个异常对象 * @param Exception $e */
public static function handle(Exception $e) {
$self = new self($e);
$self -> log();
while (@ob_end_clean());//清除所有的ob缓冲
header('HTTP/1.1 307 Temporary Redirect');
header('cache-control:no-cache,must-revalidate');
header('Expires:Tus,10 May 2015 22:35:44 GMT');//过期时间
header("Location:".$self->redirct);
exit();
}
public function log() {
error_log($this->_exception->getMessage().PHP_EOL,3, $this->_logFile);
}
}
set_exception_handler(array('ExceptionRedirctHandler','handle'));
$link = mysql_connect('localhost','root11','root');
if(!$link){
throw new Exception('数据库连接失败,抓紧查看情况');
}
404.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<title>404 Not Found</title>
<style type="text/css"> <!-- .t { font-family: Verdana, Arial, Helvetica, sans-serif; color: #CC0000; } .c { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; font-weight: normal; color: #000000; line-height: 18px; text-align: center; border: 1px solid #CCCCCC; background-color: #FFFFEC; } body { background-color: #FFFFFF; margin-top: 100px; } --> </style>
</head>
<body>
<div align="center">
<h2><span class="t">404 Not Found</span></h2>
<table border="0" cellpadding="8" cellspacing="0" width="460">
<tbody>
<tr>
<td class="c">The requested URL was not found on this server.</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>