Skip to content

Latest commit

 

History

History
288 lines (257 loc) · 8.98 KB

Q36-40.md

File metadata and controls

288 lines (257 loc) · 8.98 KB

Q36-40

标签(空格分隔): Driphp


##NO.36 isset()、empty()、is_null的区别 ###isset() 检查一个变量是否已声明,且值不为null。 换句话说:只能在变量值不是null的时候才返回true。 没有声明变量,或变量值为null,都会返回false。 ###empty() empty()用来检测一个变量是否为空。 也就是一个变量是false、空字符串、空数组、'',NULL、以及被unset()后,才返回false。 ###is_null is_null是isset()的反函数。

##NO.37 如何获取PHP的致命错误? ###问题描述 获取PHP的fatal error,比如记录到Log里面,利于我们分析线上问题,可以做线上服务的监控。 ###两个函数 ####register_shutdown_function()

register_shutdown_function($callback)

register_shutdown_function(),就把你要注册进去的function放进【假装是队列吧】,等到脚本正常退出或显示调用exit时,再把注册进去的function拉出来执行.

register_shutdown_function()调用的3种情况:

  • 脚本正常退出时;
  • 在脚本运行(run-time not parse-time)出错退出时;
  • 用户调用exit方法退出时。

####error_get_last() error_get_last() 函数获取最后发生的错误。

该函数以数组的形式返回最后发生的错误。

返回的数组包含 4 个键和值:

[type] - 错误类型 [message] - 错误消息 [file] - 发生错误所在的文件 [line] - 发生错误所在的行 ###使用方法

<?php
register_shutdown_function( "fatal_handler" );

function fatal_handler() {
  $errfile = "unknown file";
  $errstr  = "shutdown";
  $errno   = E_CORE_ERROR;
  $errline = 0;

  $error = error_get_last();

  if( $error !== NULL) {
    $errno   = $error["type"];
    $errfile = $error["file"];
    $errline = $error["line"];
    $errstr  = $error["message"];
    Log::error("错误信息***");
  }
}

###强烈注意

在parse-time出错的时候,是不会调用register_shutdown_function()函数的。只有在run-time出错的时候,才会调用register_shutdown_function()。

下面我们举例说明:

####NO.1 #####error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
function test(){}
function test(){}

执行结果如下:

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/error_handler.php:6) in /Users/shuchao/Desktop/error_handler.php on line 7

#####原因分析 在执行error_handler.php的时候,由于重复定义了两个函数test(),在php的parse-time就出错了(不是run-time),所以不能回调register_shutdown_function()中的函数。

####NO.2 #####error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
if(true){
   function test(){}
}
function test(){}

执行结果如下:

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/error_handler.php:9) in /Users/shuchao/Desktop/error_handler.php on line 7
Yeah,it's worked!%

#####原因分析 我们看到,上面回调了register_shutdown_function(). 因为我们加了一个if()判断,if()里面的test()方法,相当于一个闭包,与外面的test()名称不冲突。 也就是,上面的代码在parse-time没有出错,而是在run-time的时候出错了,所以我们能够获取到fatal error。

####NO.3 #####error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}

#####test_error.php

<?php
include './error_handler.php';
function test(){}
function test(){}

执行 test_error.php的结果如下

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/test_error.php:3) in /Users/shuchao/Desktop/test_error.php on line 4

#####原因分析 当我们在运行test_error.php的时候,因为redeclare了两个test()方法,所以php的语法解析器在parse-time的时候就出错了。 所以不能回调register_shutdown_function()中的方法,不能catch住这个fatal error。

####NO.4 #####error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}

#####test_error.php

<?php
function test(){}
function test(){}

#####include_all.php

require './error_handler.php';
require './test_error.php';

执行 include_all.php的结果如下

Fatal error: Cannot redeclare test() (previously declared in /Users/shuchao/Desktop/include_all.php:2) in /Users/shuchao/Desktop/include_all.php on line 3
Yeah,it's worked!%

#####结果分析 上面我们捕获了fatal_error. 因为在运行include_all.php的时候,include_all.php本身语法并没有出错,也就是在parse-time的时候并没有出错,而是include的文件出错了,也就是在run-time的时候出错了,这个时候是能回调register_shutdown_function()中的函数的。

#####强烈建议:如果我们要使用register_shutdown_function进行错误捕捉,使用NO.4,最后一种方法,可以确保错误都能捕捉到。

##NO.38 PHP中output buffering的原理,以及相关的应用 ###php缓存过程 在请求一个PHP的过程中,实际上经过三个缓存:

  1. 程序缓存
  2. ob缓存
  3. 浏览器缓存. ###开启ob的两个方法
1.在php.ini 配置 ;output_buffering = 4096 这里去掉;号即可
2 在php页面中使用 ob_start();

通过php.ini 打开的,则作用于所有的php页面 。使用ob_start()打开则只作用于该页面 ###ob缓存的知识点

  • 在服务中,如果我们开启了ob缓存,则echo数据首先放入到ob中
  • 当PHP页面执行到最后,则会把ob缓存的数据(如果有的话), 强制刷新到程序缓存,然后通过apache对数据封装成http响应包,返 回给浏览器
  • 如果没有ob,所有的数据直接放入程序缓存。 header信息不管你是否开启ob,总是放入到程序缓存。 ###ob相关的函数 ####ob_start($callback)
//在当前页面中开启ob,注意callback
ob_start($callback);

####ob_get_contents()

//获取当前ob缓存中的内容
ob_get_contents()

####ob_get_clean()

//获取当前ob缓存中的内容,并且清空当前的ob缓存
ob_get_clean()

####ob_flush()

//将ob缓存中的内容,刷到程序缓存中,但并没有关闭ob缓存
ob_flush()

####ob_end_flush()

//关闭ob缓存,并将数据刷回到程序缓存中
ob_end_flush()

####ob_clean()

//将ob缓存中的内容清空
ob_clean()

####ob_end_clean()

//将ob缓存中的数据清空,并且关闭ob缓存
ob_end_clean()

###注意ob_start($callback)的回调

<?php
ob_start("callback_func");
function callback_func($str){
	return "callback".$str;
}
echo "123";//输出:callback123

###应用场景 ####在header()发送之前的报错 #####出错代码

<?php
echo "before_header";
header("Content-type:text/html;charset=utf-8");
echo "after_header";

输出:

Warning: Cannot modify header information - headers already sent by (output started at /Users/shuchao/Desktop/test.php:2) in /Users/shuchao/Desktop/test.php on line 3

#####解决办法 在发送header前开启ob,则所有的echo内容都会到ob里面,从而解决错误。

<?php
ob_start();
echo "before_header\n";
header("Content-type:text/html;charset=utf-8");
echo "after_header\n";

输出

before_header
after_header

##NO.39 什么是opcode?常见的opcode cache 管理工具有哪些? ###1、什么是opcode?

当解释器完成对代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。

###2、为什么要使用opcode cache? ####php脚本的生命周期 请求PHP脚本时,会经过五个步骤,如下图所示: image_1b2nnj56irfdi1g12ac1mk38jt9.png-22.6kB Zend引擎必须从文件系统读取文件、扫描其词典和表达式、解析文件、创建要执行的计算机代码(称为Opcode),最后执行Opcode。 ####启用opcode cache

每一次请求PHP脚本都会执行一遍以上步骤,如果PHP源代码没有变化,那么Opcode也不会变化,显然没有必要每次都重行生成Opcode,我们可以把Opcode缓存下来,以后直接访问缓存的Opcode岂不是更快,启用Opcode缓存之后的流程图如下所示: image_1b2nnu81v1pvjqo91ugrfbp2prm.png-33kB ###3、常见的opcode cache 管理工具有哪些? Optimizer+(Optimizer+于2013年3月中旬改名为Opcache,PHP 5.5集成Opcache)、eAccelerator、xcache、APC ...

##NO.40 什么是闭包?为什么要使用闭包? ###什么是闭包? 闭包,顾名思义,就是把馒头变成包子~

馒头全是面粉,包上馅就成了包子

包子是带馅的馒头

闭包是自带运行环境的函数

###为什么用闭包? 闭包的目的是用来扩大变量的作用域的。