自己实现的一个PHP错误异常日志捕获类

自己实现的一个PHP错误异常日志捕获类

特性:
输出到控制台/文件/自定义方法
可以通过错误等级进行过滤,有总开关可以关闭一切错误输出
易用
废话不多说,上代码:

<?php
/**
 * Created by PhpStorm.
 * User: tim
 * Date: 2019/1/30
 * Time: 15:41
 * 功能:日志函数,用与捕获错误或者输出信息到指定的输出流。
 * 用法:程序的入口入口函数调用,index.php/init.php等,生命周期内全局有效。
 * 原理:
 * 1. set_error_handler() 函数设置用户自定义的错误处理函数。
 * 该函数用于创建运行时期间的用户自己的错误处理方法。
 * 该函数会返回旧的错误处理程序,若失败,则返回 null。
 * 2. set_exception_handler() 函数设置用户自定义的异常处理函数。
 * 该函数用于创建运行时期间的用户自己的异常处理方法。
 * 该函数会返回旧的异常处理程序,若失败,则返回 null。
 * 3. debug_backtrace() 函数用于获取函数调用轨迹[发现不好用]
 * 4. error_get_last() 获取错误信息 [发现不好用]
 * 5. register_shutdown_function() 程序运行结束回调函数 [发现没嘛用]
 * 6. libxml_get_last_error() 获取错误信息 [发现不好用]
 *
 * 函数组织形式,依据日志记录流程自顶部向下分层:
 * 接口层: 设置是否输出、输出的错误级别、输出到哪里、手动输出。
 * 错误捕捉层:对于错误的捕捉、对于异常的捕捉
 * 时间格式化层:为错误信息附上时间戳
 * 输出过滤层:再此处实现错误级别过滤
 * 输出抽象层:在此层实现总开关和输出函数实例调用
 * 输出层:输出方式的具体实现
 *
 * 其他说明:
 * 1. 为了注册错误异常处理函数,因此有一个构造函数
 * 2. 为了Log::log()函数可以被随处调用,因此大多数函数和变量为static
 * 3. 为了配置可以链式调用,因此不使用静态方法(强迫症)
 * 4. 错误类型用中文阅读性不好,建议换成英文
 */

class Log
{
    private  static $logfile = __DIR__.'/log_password.txt';
    private  static $debug = true;
    private  static $out_level = 30719;
    private  static $out_method_function='Log::out_console';
    private  static  $errmap = array(
        '0'  =>  '错误要了命了  ',
        '1'  =>  '致命运行时错误',
        '2'  =>  '运行时警告    ',
        '4'  =>  '编译语法错误  ',
        '8'  =>  '运行时通知    ',
        '16' =>  '初始化致命错误',
        '32' =>  '初始化警告    ',
        '64' =>  '致命编译错误  ',
        '128'=>  '编译时警告    ',
        '256'=>  '用户自定义错误',
        '512'=>  '用户自定义警告',
        '1024'=> '用户自定义通知',
        '2048'=> 'PHP兼容性建议 ',
        '4096'=> '可捕捉致命错误',
        '8192'=> '运行时通知    ',
        '16384'=>'用户产生的警告',
        '30719'=>'其他警告WARNING'
    );

    public function  __construct(){
        @set_error_handler(array(&$this, 'error_handler'));
        @set_exception_handler(array(&$this, 'exception_handler'));
//        @register_shutdown_function(array(&$this,'shutdown_handler')); // 似乎用不到,有错没错,程序运行结束就调用
        $this->init();
    }

    // 还原配置更改
    public function init(){
        $this->is_debug(true)->out_level(30719)->out_method('Log::out_console');
        return $this;
    }

    // 通过任意实例更改是否输出配置
    public function is_debug($is_debug=true){
        self::$debug=$is_debug;
        return $this;
    }

    // 通过
    public function out_level($level=30719){
        self::$out_level=$level;
        return $this;
    }

    public function out_method($out_method=null){
        $out_method = is_null($out_method)?self::$out_method_function:$out_method;
        self::$out_method_function = $out_method;
        return $this;
    }

    // 手动输出信息 类似与 console.log()
    public static function log(...$strs){
        $str = '';
        foreach($strs as $s){
            if (is_array($s) || is_object($s)) $s = json_encode($s,256);
            $str .= $s;
        }
        self::out(self::format($str.'  '.self::trace()));
        return self::$debug;
    }


//E_STRICT类型
    public function error_handler($type, $message, $file, $line)
    {
//        echo "出错";
        $msg = self::format($message.' '.$file.' '.$line,self::$errmap[$type]);
        self::whether_out($msg,$type);
    }

    public function exception_handler($error){
//        echo "发生异常";
        $msg = self::format($error->getMessage().' '.$error->getFile().' '.$error->getLine().' ',
            self::$errmap[$error->getCode()]);
        self::whether_out($msg,$error->getCode());
    }


    public function shutdown_handler(...$args){
//        echo "运行结束";
        print_r(error_get_last());
        print_r(debug_backtrace());
        print_r($args);
    }

    // 是否输出,总开关开 && 错误级别高于阈值
    private static function whether_out($str,$type=30719){
        if(intval($type)<=self::$out_level)
            self::out($str);
    }

    // 重写此函数可以写到Socket/Db/http/file
    private static function out($str){
        if(self::$debug) call_user_func(self::$out_method_function,$str);
    }

    // 输出到文件
    private static function out_file($str){
        file_put_contents(self::$logfile,$str, FILE_APPEND);
    }

    private static function out_socket($str){
        // TODO
    }

    private static function out_db($str){
        // TODO
    }

    private static function out_browser($str){
        echo "<script>console.log('$str')</script>";
    }

    private static function out_console($str){
        echo $str.PHP_EOL;
    }

    // 调用轨迹
    public static function trace(){
        $separator = " ";
        $trace = debug_backtrace();
        $tra='';
        $count=0;
        foreach ($trace as $index => $step) {
            $call = $step['class'].'::'.$step['function'];
            if($call=='Log::trace'
            || $call=='Log::format' || ++$count>2)continue;

            $tra .= $step['file'];
            $tra .= ':'.$step['line'].'行'.$separator;
//            $tra .= isset($step['class'])?(' '.$step['class'].'::'):'';
//            $tra .= isset($step['function'])?(''.$step['function'].'()'):'';
//            $tra .= isset($step['args'][0])?json_encode($step['args']):'';
//            $tra .= ') : ';
        }
        return $tra;
    }

    // 附上时间和错误类型
    private static function format($log='msg null',$type='INFO          '){
        $separator = " => ";
        $info = date('Y-m-d H-i-s ',time())
            .@sprintf('%06d',1000000*(floatval(microtime())-floor(floatval(microtime()))))
            .$separator.$log.PHP_EOL;
        return $type.'  '.$info;
    }
}

代码细节没耐心看?直接来个Demo

  1. 默认直接输入到控制台

    <?php
    require 'Log.php';
    $log = new Log();
    
    1/0;
    //$log->is_debug(false)->out_method('Log::out_file');
    $t=array();
    print($t[0]);
    
    Log::log("hahahahahah");
    
    function zzzzh($a,$b){
        Log::log("PHP是什么意思?");
        echo "in zzzzh".$a.$b;
    }
    
    $log->is_debug(true);
    try{
        zzzzh(2345);
    }catch(Exception $e){
        print_r($e);
    }
    
    

    在这里插入图片描述

  2. 演示总开关,更改输出方式

    <?php
    require 'Log.php';
    $log = new Log();
    
    1/0;
    $log->is_debug(false)->out_method('Log::out_file');
    $t=array();
    print($t[0]);
    
    Log::log("hahahahahah");
    
    function zzzzh($a,$b){
        Log::log("PHP是什么意思?");
        echo "in zzzzh".$a.$b;
    }
    
    $log->is_debug(true);
    try{
        zzzzh(2345);
    }catch(Exception $e){
        print_r($e);
    }
    
    

    在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值