如今在一家公司作PHP后台开发程序猿(咱们组没有前端,作活动时会作前端的东西),刚开始到公司的时候花2个周赶出了一个前端加后台的活动(记得当时作不出来周末加了两天班、、、),到如今过去4个多月了,能够用一下午秒掉一个不是很复杂的活动,固然了如今作的时候会考虑不少东西,好比说扩展性、可重用性,由于作的多了,会积累不少相似小插件的东西,因此会很快。。。。。。可是我发现成天“站在需求里面作需求”不好劲,这样不会学到系统的、框架类的东西,由于都被琐碎的需求给困住了,没有时间去作一些框架重要部分的东西,并且当你的同事、上司习惯了你去作那些事的时候,每次遇到那些没技术含量的但又不得不作的东西都会坚决果断的推给你(自私点的说,每一个程序猿都像我同样吧,都想掌握一块有技术含量的东西,这样才有程序猿的自豪感),长此以往你就会习惯、、、、、、这样真的很惨,因此,我会抽出点时间来学习下框架中的东西,争取不作一个简单的码农。php
接触过php框架的朋友们可能都知道,日志在项目中的重要做用了,他能够帮助咱们定位错误的位置,让程序更友好(处理得当的话不会直接抛出一大堆只有程序猿才真正动的英文),调试的时候也会很方便,还能够记录一些重要的操做等等,总之一个完整的项目要是没了日志系统,就已经开发的路上布满了荆棘、坑洼,确定会磕磕绊绊的。前端
要掌握PHP日志系统,必须先对这几点东西了解透彻。git
1 set_exception_handler(callback $exception_handler); //异常捕获自定义处理函数注册 github
1 set_error_handler(callback $error_handler); //错误捕获自定义处理函数注册 bootstrap
1 register_shutdown_function(callback $callback); //程序执行时异常终止错误捕获处理函数注册 数组
这三个函数在错误处理控制中给开发者提供了很大的自主空间,在日志系统中记录日志信息有他们的功劳。php框架
在程序中出现异常(exception)问题时,php内核会抛出异常错误,而后将错误信息打印给使用者,若是注册了exception处理函数,php抛出的异常会转给自定义的注册的异常捕获函数,这个函数里面包含了咱们要作的处理,记录错误信息(包括错误详细内容、错误位置),该函数处理完异常后,异常就会终止。app
当程序中出现error时,咱们注册的error处理函数会在函数中将错误信息转化为一个错误异常对象传递给异常处理函数,也就是第一步的$exception_handler函数。框架
当成续重出现shutdown错误时,会执行咱们注册的异常终止处理函数,该函数经过error_get_last()获取到最后的shutdown时的错误对象,接着和上一部同样,生成一个error exception对象,将该对象传递给咱们注册的异常处理函数。函数
能够看到,其实不论是异常仍是错误,都是将本身的信息转化为异常处理函数认识的异常信息,而后交给异常处理函数处理,非异常信息就像化了妆的女人同样,异常处理程序不认识这些非异常信息,只有将装卸掉(非异常信息本身转化为异常信息,准确的说应该是抛出),异常处理才认识。
php日志系统中的错误处理流程
那么如今问题来了,这几个函数通常会配合一个异常处理类库,加上一个错误日志记录类库来进行工做,异常处理类库中包含要注册的3个函数,日志记录类库在$exception_handler中调用,用来合理的记录和放置日志文件的位置,上面说到的几个函数通常是在程序框架入口处进行加载注册的,就像下面这样:
这里面用的是array(class,function)这种方式。
1 set_exception_handler(array("Myexception","exceptionHandler")); 2 set_error_handler(array("Myexception","errorHandler")); 3 register_shutdown_function(array("Myexception","shutdownHandler"));
第一部分介绍到的东西只是对异常、错误、shutdown进行了捕获,这只是第一步,接下来还要对捕获到的信息进行合理的处理,好比说记录这些日志信息到本地文件系统中(这个操做是在array("Myexception","exceptionHandler")),这个地方就用到了日志记录类库。(下面要说的类库是借鉴了kohana日志系统的设计)。
日式日志记录也很简单只要作的将信息添加到文件末尾就行,这个很容易实现,相信你们均可以本身实现,可是要设计出一个便捷的、高效的、扩展的日志记录类库就不那么简单了,要通过长时间的实践总结优化才能够,kohana框架中的日志记录类库已经比较成熟了,所以这里拿来借鉴。
相信使用过kohana的用户必定对kohana框架中的日志记录比较熟悉,不熟悉也不要紧,我下面会大概的说说,在kohana源码中的application/bootstrap.php文件中的第109——112行能够看到下面的代码:
109 /** 110 * Attach the file write to logging. Multiple writers are supported. 111 */ 112 Kohana::$log->attach(new Log_File(APPPATH.'logs'));
这个就是添加一个日志记录对象到日志对象中,注意橄榄色打底的俩个,他们是不一样的类库实例,在kohana中,日志记录对象分为两部分,第一部分就是日志对象,用来维护一个日志记录对象的列表,这个要怎么理解呢,其实就像一个容器,里面包含了一个或多个日志记录对象(这个就是第二部分,这些日志记录对象才是真正来记录日志的),还有每一个对象要记录的错误等级的数组,当知足错误等级的时候才会去记录,不知足就会略掉。下面是我本身简化重命名后的日志记录方式:
1 self::$log = Log::instance(); 2 self::$log->attach(new Logwriter("./data/debug"),Log::DEBUG); 3 self::$log->attach(new Logwriter("./data/notice"),Log::NOTICE);
我这里面为了更好地理解,将“容器”命名为Log,记录的实例命名为Logwriter,能够看到我在程序入口处很容易的添加了两不一样的日志种类,第一个是记录全部错误号比Log::DEBUG小的错误(错误级别比他高),并按规则记录在文件夹./data/debug下面,第二个是记录级别等于或高于Log::NOTICE的错误,固然了你还能够更详细制定具体哪些错误好,传递数组就好了,这个就是我感受方便、快捷的地方,咱们能够根据需求来添加错误日志、分不一样的日志目录,下面看一幅图也许会有助于理解:
log与logwriter的关系
经过上面的图你就会看到Log是一个容器,包含了具体的不一样的logwriter对象,每一个对象可能要记录不一样的信息,当错误信息要刷到文件中的时候,会运行每个Logwriter实例,看看本身是否要记录errormessage中的错误,errormessage中的level不包含在Logwriter内时忽略。
这本分和第一部分怎么合做的呢?其实很简单,当exception捕获的异常时会调用添加一条错误信息(包括错误位置、错误代号、错误信息等信息)到Log容器中的errormessage数组中,而后当程序结束以后在将这些信息写入文件,这里还要注意下,也许你在阅读kohana代码是发现没有明显的直接写入到日志中去,这里面kohana优化的比较好,由于php的一次执行可能出现多个错误,若是来一个错误你就去记录一次这样会在程序返回以前占用多余的io和时间,因此kohana的作法是默认将全部的错误、异常、日志存放在Log::$errormessage中,并在实例化的时候讲Log中的writer操做注册register_shutdown_function,这个函数的做用是在程序异常终止或者执行完成以后执行,前面第一部分也有使用到,这样日志记录就不会对本次php的执行产生带大的影响。
到这里你应该已经了解了日志系统的大概了,已经能够本身编写一个”日志系统”来使用了,下面看看个人”日志系统“的例子,这是github地址,里面有代码和例子,须要的话能够看看。
https://github.com/AizuYan/phplog.git
本文版权归做者(luluyrt@163.com)和博客园共有,未经做者本人赞成禁止任何形式的转载,转载文章以后必须在文章页面明显位置给出做者和原文链接,不然保留追究法律责任的权利。