PHP从基础到高级总结

一、 PHP基础

基础类型: integer, string,  boolean, float, array, object, resource, NULL
    标量类型: boolean、integer、float/double、string
    复合类型: array 、 object
    特殊类型: resource、 null

超级全局变量:
    $GLOBALS, $_SERVER, $_REQUEST, $_POST, $_GET, $_COOKIE, $_FILES, $_ENV, $_SESSION

    $_POST
        能够接收类型:
            application/x-www-form-urlencoded
            multipart/form-data
    php://input
        访问请求的原始数据的只读流, 包括$_POST支持的类型和application/json
            //php
            $_POST = json_decode(file_get_contents('php://input'),true);

    $_SERVER['PHP_SELF']            返回当前执行脚本的文件名。
    $_SERVER['GATEWAY_INTERFACE']   返回服务器使用的 CGI 规范的版本。
    $_SERVER['SERVER_ADDR']         返回当前运行脚本所在的服务器的 IP 地址。
    $_SERVER['SERVER_NAME']         返回当前运行脚本所在的服务器的主机名(比如 www.baidu.cn)。
    $_SERVER['SERVER_SOFTWARE']     返回服务器标识字符串(比如 Apache/2.2.24)。
    $_SERVER['SERVER_PROTOCOL']     返回请求页面时通信协议的名称和版本(例如,“HTTP/1.0”)。
    $_SERVER['REQUEST_METHOD']      返回访问页面使用的请求方法(例如 POST)。
    $_SERVER['REQUEST_TIME']        返回请求开始时的时间戳(例如 1577687494)。
    $_SERVER['QUERY_STRING']        返回查询字符串,如果是通过查询字符串访问此页面。
    $_SERVER['HTTP_ACCEPT']         返回来自当前请求的请求头。
    $_SERVER['HTTP_ACCEPT_CHARSET'] 返回来自当前请求的 Accept_Charset 头( 例如 utf-8,ISO-8859-1)
    $_SERVER['HTTP_HOST']           返回来自当前请求的 Host 头。
    $_SERVER['HTTP_REFERER']        返回当前页面的完整 URL(不可靠,因为不是所有用户代理都支持)。
    $_SERVER['HTTPS']               是否通过安全 HTTP 协议查询脚本。
    $_SERVER['REMOTE_ADDR']         返回浏览当前页面的用户的 IP 地址。
    $_SERVER['REMOTE_HOST']         返回浏览当前页面的用户的主机名。
    $_SERVER['REMOTE_PORT']         返回用户机器上连接到 Web 服务器所使用的端口号。
    $_SERVER['SCRIPT_FILENAME']     返回当前执行脚本的绝对路径。
    $_SERVER['SERVER_ADMIN']        该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。
    $_SERVER['SERVER_PORT']         Web 服务器使用的端口。默认值为 “80”。
    $_SERVER['SERVER_SIGNATURE']    返回服务器版本和虚拟主机名。
    $_SERVER['PATH_TRANSLATED']     当前脚本所在文件系统(非文档根目录)的基本路径。
    $_SERVER['SCRIPT_NAME']         返回当前脚本的路径。
    $_SERVER['SCRIPT_URI']          返回当前页面的 URI。


PHP全局处理:
    register_shutdown_function //注册一个会在php中止时执行的函数
    set_error_handler          //设置用户自定义的错误处理函数(用户级别错误,trigger_error)
    set_exception_handler      //设置用户自定义的异常处理函数(用户级别异常,throw)
    session_set_save_handler   //设置用户自定义会话存储函数
    spl_autoload_register      //自动加载器, 区别于__auto_load()只能加载一次

魔术变量:
    __LINE__    文件中的当前行号
    __FILE__    文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。
    __DIR__     文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。
    __FUNCTION__    函数被定义时的名字(区分大小写)。
    __CLASS__   类被定义时的名字。
    __METHOD__  类中的方法被定义时的名字。
    __NAMESPACE__   当前命名空间的名称。

PHP魔术方法:
    对象析构、解构
        __construct     对象析构函数
        __destruct      对象解构函数
    属性重载
        __set          给不可访问属性赋值时调用
        __get          读取不可访问属性的值时调用
        __isset        对不可访问属性调用 isset() 或 empty() 时调用
        __unset        对不可访问属性调用 unset() 时调用
    方法重载
        __call         在对象中调用一个不可访问方法时调用
        __callStatic   在静态上下文中调用一个不可访问方法时调用, 静态方式调用该方法
    对象序列化
        __sleep        对对象进行serialize()时调用, 用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
        __wakeup       unserialize()时调用, 用于预先准备对象需要的资源。
    对象字符串化
        __toString     类被当成字符串时返回一个字符串。
    对象调用函数化
        __invoke       当尝试以调用函数的方式调用一个对象时调用
    导出类
        __set_state    当调用 var_export() 导出类时, 静态方式调用该方法
        __debugInfo    当调用var_dump() 打印类时,如果定义该方法则只会打印该方法返回值,否则打印全部成员



设置、异常、错误处理:
    设置
        ini_set('max_execution_time', -1);              脚本执行的超时时间
        ini_set('default_socket_timeout', -1);          基于socket流的默认超时时间
        ini_set('memory_limit', -1);                    设置脚本执行最大内存
        ini_set('error_reporting', E_ALL | E_STRICT);   错误级别
        ini_set('display_errors', 'On');                开启错误回写,开启状态下,若出现错误,则报错,出现错误提示
        ini_set('log_errors', 'On');                    开启错误日志, 记录到error_log指定的路径
        ini_set('date.timezone','Asia/Shanghai');       时区设置
        error_reporting(7);                             错误级别,同ini配置
        set_time_limit(0);                              设置脚本最大执行时间,同ini配置, 只影响脚本本身执行的时间
        ignore_user_abort();                            关闭浏览器,PHP后台继续运行

    函数、描述:
        debug_backtrace()   生成 backtrace。
        debug_print_backtrace() 打印 backtrace。
        error_get_last()    返回最后发生的错误。
        error_log() 向服务器错误记录、文件或远程目标发送错误消息。
        error_reporting()   规定报告哪个错误。
        restore_error_handler() 恢复之前的错误处理程序。
        restore_exception_handler() 恢复之前的异常处理程序。
        set_error_handler() 设置用户自定义的错误处理函数。
        set_exception_handler() 设置用户自定义的异常处理函数。
        trigger_error() 创建用户级别的错误消息。
        user_error()    trigger_error() 的别名。
    错误类型:
        1       E_ERROR 运行时致命的错误。不能修复的错误。终止执行脚本。
        2       E_WARNING   运行时非致命的错误。不终止执行脚本。
        4       E_PARSE 编译时语法解析错误。解析错误仅仅由分析器产生。
        8       E_NOTICE    运行时通知。表示脚本遇到可能会表现为错误的情况,但是在可以正常运行的脚本里面也可能会有类似的通知。
        16      E_CORE_ERROR    在 PHP 初始化启动过程中发生的致命错误。该错误类似 E_ERROR,但是是由 PHP 引擎核心产生的。
        32      E_CORE_WARNING  PHP 初始化启动过程中发生的警告 (非致命错误) 。类似 E_WARNING,但是是由 PHP 引擎核心产生的。
        64      E_COMPILE_ERROR 致命编译时错误。类似 E_ERROR, 但是是由 Zend 脚本引擎产生的。
        128     E_COMPILE_WARNING   编译时警告 (非致命错误)。类似 E_WARNING,但是是由 Zend 脚本引擎产生的。
        256     E_USER_ERROR    用户产生的错误信息。类似 E_ERROR, 但是是由用户自己在代码中使用PHP函数 trigger_error()来产生的。
        512     E_USER_WARNING  用户产生的警告信息。类似 E_WARNING, 但是是由用户自己在代码中使用 PHP 函数 trigger_error() 来产生的。
        1024    E_USER_NOTICE   用户产生的通知信息。类似 E_NOTICE, 但是是由用户自己在代码中使用 PHP 函数 trigger_error() 来产生的。
        2048    E_STRICT    启用 PHP 对代码的修改建议,以确保代码具有最佳的互操作性和向前兼容性。
        4096    E_RECOVERABLE_ERROR 可被捕捉的致命错误。它表示发生了一个可能非常危险的错误,但是还没有导致 PHP 引擎处于不稳定的状态。 如果该错误没有被用户自定义句柄捕获 (参见 set_error_handler()),将成为一个 E_ERROR 从而脚本会终止运行。
        8192    E_DEPRECATED    运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。
        16384   E_USER_DEPRECATED   用户产生的警告信息。类似 E_DEPRECATED, 但是是由用户自己在代码中使用 PHP 函数 trigger_error() 来产生的。
        32767   E_ALL   E_STRICT 除非的所有错误和警告信息。
垃圾回收机制
    < 5.2
        如果refcount值为0,PHP会当做垃圾释放掉
        这种回收机制有缺陷,对于环状引用的变量无法回收
    >= 5.3
        发现一个zval容器中的refcount在增加,说明不是垃圾
        发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收
        发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象。
        当缓冲区达到了临界值,PHP会自动调用一个方法去遍历每一个值,如果发现是垃圾就清理

    引用计数:
        ## php4-php6
        * php变量存在一个叫"zval"的变量容器中。
        * zval变量容器包含:变量值(value)、变量类型(type)、是否是属于引用集合(is_ref__gc)、引用次数(refcount__gc)
        * 新变量中"is_ref"被默认设置为 FALSE,因为没有任何自定义的引用生成。
        * xdebug_debug_zval()显示"refcount"和"is_ref"的值。
        * 把一个变量赋值给另一变量将增加引用次数(refcount)。


    回收机制:
        < 5.2
            如果refcount值为0,PHP会当做垃圾释放掉
            这种回收机制有缺陷,对于环状引用的变量无法回收
        >= 5.3
            发现一个zval容器中的refcount在增加,说明不是垃圾
            发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收
            发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象。
            当缓冲区达到了临界值,PHP会自动调用一个方法去遍历每一个值,如果发现是垃圾就清理
        具体:
         * 使用引用计数器和同步算法来进行处理
         * 把所有可能根变量容器,放在根缓冲区,在根缓冲区满了时,才对缓冲区内部所有不同的变量容器执行垃圾回收操作。
         * 引用计数减少,将会推到垃圾回收周期,通过检查哪些变量容器的引用次数是零,来发现哪部分是垃圾。
         * 引用计数减少到零,所在变量容器将被清除(free)。

二、 PHP-fpm

基本操作
    #启动PHP服务
    /usr/local/php/sbin/php -S 127.0.0.1:8080 -t [目录] [&]

    #启动php-fpm
    /usr/local/php/sbin/php-fpm
    /usr/local/php/sbin/php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm.conf

    #关闭php-fpm
    kill -INT `cat /usr/local/php/var/run/php-fpm.pid`

    #重启php-fpm
    kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

工作原理
    PHP提供的SAPI
        apache2handler 、mode_php
        fastcgi
        cli
        isapi

    FastCGI的工作原理:
        1. Server启动时载入FastCGI进程管理器
        2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Server的连接
        3. 当客户端请求到达Server时,FastCGI进程管理器选择并连接到一个CGI解释器。
           Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
        4. FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Server。
            当FastCGI子进程关闭连接时,请求便告处理完成。
            FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。

    运行模式
        static      静态模式,启动时分配固定的worker进程。
        ondemand    按需分配,当收到用户请求时fork worker进程。
        dynamic     动态模式,启动时分配固定的进程。伴随着请求数增加,在设定的浮动范围调整worker进程。

    进程池参数
        pm.max_children:限定php-fpm的最大进程数,静态模式默认分配work数。
        pm.start_servers:动态方式下的起始php-fpm进程数量。
        pm.min_spare_servers:动态方式空闲状态下的最小php-fpm进程数量。
        pm.max_spare_servers:动态方式空闲状态下的最大php-fpm进程数量。


    运行原理
        master进程负责CGI、PHP公共环境的初始化及事件监听操作。
        worker进程负责请求的处理功能。在worker进程处理请求时,无需再次初始化PHP运行环境,这也是php-fpm性能优异的原因之一。

        master:
            1. cgi初始化阶段:
                分别调用fcgi_init()和 sapi_startup()函数,注册进程信号以及初始化sapi_globals全局变量。

            2. php环境初始化阶段:
                由cgi_sapi_module.startup 触发。
                实际调用php_cgi_startup函数,而php_cgi_startup内部又调用php_module_startup执行。
                php_module_startup主要功能:
                    a).加载和解析php配置;
                    b).加载php模块并记入函数符号表(function_table);
                    c).加载zend扩展 ;
                    d).设置禁用函数和类库配置;
                    e).注册回收内存方法;

            3. php-fpm初始化阶段:
                执行fpm_init()函数。
                负责解析php-fpm.conf文件配置,获取进程相关参数(允许进程打开的最大文件数等),初始化进程池及事件模型等操作。

            4. php-fpm运行阶段:
                执行fpm_run() 函数,运行后主进程发生阻塞。
                该阶段分为两部分:fork子进程 和 循环事件。fork子进程部分交由fpm_children_create_initial函数处理。
                循环事件部分通过fpm_event_loop函数处理,其内部是一个死循环,负责事件的收集工作。

        worker:
            1. 接收客户端请求:
                执行fcgi_accept_request函数,其内部通过调用accept 函数获取客户端请求。

            2. 处理请求阶段:
                首先,分别调用fpm_request_info、php_request_startup获取请求内容及注册全局变量($_GET、$_POST、$_SERVER、$_ENV、$_FILES);
                然后根据请求信息调用php_fopen_primary_script访问脚本文件;
                最后交给php_execute_script执行。php_execute_script内部调用zend_execute_scripts方法将脚本交给zend引擎处理。

            3. 请求结束阶段:
                执行php_request_shutdown函数。
                此时 回调register_shutdown_function注册的函数及__destruct()方法,发送响应内容、释放内存等操作。

三、PHP新特性

PHP5的zvalue面临的问题:
        1. 结构体的大小为24个字节
        2. 没有预留任何的自定义字段
        3. PHP的zval大部分都是按值传递, 写时拷贝的值, 但对象和资源, 他们永远都是按引用传递,所以它有俩套引用计数, 一个是zval中的, 另外一个是obj自身的计数,结构变得复杂, 维护性降低
        4. PHP应用的写时分离是的复制性能问题
        5. 许多局部变量使用堆内存分配
    
        <?php
            $array = range(1, 100000);
            function dummy($array) {}
    
            $i = 0;
            $start = microtime(true);
            while($i++ < 100) {
                dummy($array);
            }
            printf("Used %sS\n", microtime(true) - $start);
    
            $i = 0;
            $b = &$array; //注意这里, 假设我不小心把这个Array引用给了一个变量
            $start = microtime(true);
            while($i++ < 100) {
                dummy($array);
            }
            printf("Used %sS\n", microtime(true) - $start);
        ?>
    
Zval容器变化
    ### version < 7
    zval变量容器 {
        value,      -- 变量值(16字节)
        type,       -- 变量类型(2字节)
        is_ref__gc  -- 是否是属于引用集合(2字节)
        refcount__gc -- 引用次数(4字节)
    }
    
    ### ### version >= 7
    zval变量容器 {
        value,          -- 变量值(16字节)
        u1联合体 {
            type_info   -- 类型信息
            ZEND_ENDIAN_LOHI_4  -- 简化赋值, 四个字符变量的结构体
        }
        u2联合体 {
            var_flags
            next        --hash碰撞链
            cache_slot
            lineno      --行号(AST,对象生成树槽点)
            num_args
            fe_pos      --foreach位置
            fe_iter_idx --foreach迭代器索引
        }
    }
    
    具体:
        对于在zval的value字段中能保存下的值, 就不再对他们进行引用计数了, 而是在拷贝的时候直接赋值, 这样就省掉了大量的引用计数相关的操作
        ZEND_ENDIAN_LOHI_4作用是简化赋值,保证在大端或者小端的机器上,定义的字段都按照一样顺序排列存储, 从而我们在赋值的时候, 不需要对它的字段分别赋值, 而是可以统一赋值

四、 PHP安全机制

攻击手段: SQL注入、XSS、CSRF、DDOS、Session固定攻击、 Session劫持攻击、文件上传漏洞

PHP漏洞:
    1. 精度绕过缺陷
        floor((0.1+0.7)*10)  // = 7
    2. 类型转换的缺陷
        var_dump('66hh' == 66); // true
    3. 松散比较符的缺陷
        var_dump(0=="gg");  //true
        var_dump(0==="gg"); //false
        var_dump(1=="gg");  //false
    4. md5绕过(Hash比较缺陷)
        var_dump(md5('QNKCDZO') == md5(240610708));
        字符串       md5
        QNKCDZO     0e830400451993494058024219903391
        240610708   0e462097431906509019562988736854
        aabg7XSs    0e087386482136013740957780965295
        aabC9RqS    0e041022518165728065344349536299
        s878926199a 0e545993274517709034328855841020
    6. sha1()与md5()加密函数漏洞缺陷
        var_dump(sha1($_GET['name']) === sha1($_GET['password']))   //请求/?name[]=a&password[]=b
    7. 字符串处理函数漏洞缺陷
        函数接受到了不符合的类型,例如数组类型,函数将发生错误。
        在5.3之前, 显示了报错的警告信息后,将return 0, 即判断其为正确。
    8. parse_str函数变量覆盖缺陷
        parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量。

参考:
    http://www.freebuf.com/articles/rookie/161474.html
    
提示站点安全系数:
    register_globals = Off   -- 关闭全局注册变量功能
    error_reporting = E_ALL|E_STRICT   -- 配置预警模式,如果有未初始化的,就会预警
    display_errors = On      -- 不显示页面错误信息
    log_errors = On          -- 保存错误信息到本地
    allow_url_include = Off  -- 不允许加载远程php文件
    allow_url_fopen   = Off  -- 不允许打开远程文件(影响fopen,file_put_contents)
    magic_quotes_gpc  = On   -- get,post,cookie变量的过滤,过滤有单引号,双引号,反斜杠,空字符,都用反斜杠转义($_SERVER变量不会过滤)
    magic_quotes_runtime= On -- 对文件或者数据库中取出的数据过滤
    safe_mode = On           -- 限制函数使用权限和操作目录文件权限等功能。检验用户是否有操作文件权限。
    disable_functions        -- 禁用的函数
    expose_php  = Off        -- 隐藏php版本信息
    display_startup_errors = Off -- 不在页面显示php程序启动时产生的错误

站点攻击:
    1.跨网站脚本攻击(Cross Site Scripting, XSS)
        描述:
            攻击者将恶意代码注入到网页上,其他用户在加载网页时就会执行代码,
            攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
        例如:
            <?php  echo "欢迎您,".$_GET['name'];
            弹出一个对话框:http://localhost/test.php?name=<script>alert(123456)</script>
        防范方法:
            使用htmlspecialchars函数将特殊字符转换成HTML编码,过滤输出的变量

    2.跨网站请求伪造攻击(Cross Site Request Forgeries, CSRF)
        描述:
            攻击者伪造目标用户的HTTP请求,然后此请求发送到有CSRF漏洞的网站,网站执行此请求后,引发跨站请求伪造攻击。
            攻击者利用隐蔽的HTTP连接,让目标用户在不注意的情况下单击这个链接,
            由于是用户自己点击的,而他又是合法用户拥有合法权限,所以目标用户能够在网站内执行特定的HTTP链接,从而达到攻击者的目的。
        例如:
            某个购物网站购买商品时,采用http://www.shop.com/buy.php?item=watch&num=100
            item参数确定要购买什么物品,num参数确定要购买数量,如果攻击者以隐藏的方式发送给目标用户链接
            ,那么如果目标用户不小心访问以后,购买的数量就成了100个。
        防范方法:
            1、检查网页的来源
            2、检查内置的隐藏变量
            3、使用POST,不要使用GET,处理变量也不要直接使用$_REQUEST

    3. Session固定攻击(Session Fixation)
        描述:
            攻击者预先设定session id,让合法用户使用这个session id来访问被攻击的应用程序,一旦用户的会话ID被成功固定,攻击者就可以通过此session id来冒充用户访问应用程序。
        例如:
            1.攻击者访问网站http:///www.bank.com,获取他自己的session id,如:SID=123;
            2.攻击者给目标用户发送链接,并带上自己的session id,如:http:///www.bank.com/?SID=123;
            3.目标用户点击了http:///www.bank.com/?SID=123,像往常一样,输入自己的用户名、密码登录到网站;
            4.由于服务器的session id不改变,现在攻击者点击http:///www.bank.com/?SID=123,他就拥有了目标用户的身份,可以为所欲为了。
        防范方法:
            1.定期更改session id
            2.更改session的名称, session的默认名称是PHPSESSID
            3.关闭透明化session id , int_set("session.use_trans_sid", 0);
            4.只从cookie检查session id
                int_set("session.use_cookies", 1);//表示使用cookies存放
                session id int_set("session.use_only_cookies", 1);//表示只使用cookies存放session id
            5.使用URL传递隐藏参数
                $sid = md5(uniqid(rand()), TRUE));
                $_SESSION["sid"] = $sid;

    4. Session劫持攻击(Session Hijacking)
        描述:
            攻击者利用各种手段来获取目标用户的session id。
            一旦获取到session id,那么攻击者可以利用目标用户的身份来登录网站,获取目标用户的操作权限。
            攻击者获取目标用户session id的方法:
                a.暴力破解:尝试各种session id,直到破解为止;
                b.计算:如果session id使用非随机的方式产生,那么就有可能计算出来;
                c.窃取:使用网络截获,xss攻击等方法获得
        防范方法:
            1.定期更改session id
            2.更改session的名称
            3.关闭透明化session id
            4.设置HttpOnly。通过设置Cookie的HttpOnly为true,可以防止客户端脚本访问这个Cookie,从而有效的防止XSS攻击。

参考:
    PHP安全之Web攻击: http://www.cnblogs.com/luyucheng/p/6234524.html
    PHP代码安全杂谈: http://www.freebuf.com/articles/rookie/161474.html
    
    接口安全:
        Token机制, 分配appkey, appSecret
        数据校验,  sign+timestamp+token
        过载保护
        异常封装

五、栈内存和堆内存的区别:

    程序的内存分配
        栈(stack):有编译器自动分配和释放,存放函数的参数、局部变量、临时变量、函数返回地址等;
        堆(heap):一般有程序员分配和释放,如果没有手动释放,在程序结束时可能由操作系统自动释放, 稍有不慎会引起内存泄漏。

    申请后系统的响应
        栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出。
        堆:在记录空闲内存地址的链表中寻找一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

    申请大小限制
        栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。
            如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
        堆:堆是向高地址扩展的数据结构,是不连续的内存区域。堆的大小受限于计算机系统中有效的虚拟内存。
            由此可见,堆获得的空间比较灵活,也比较大。

    分配效率
        栈:由系统自动分配,速度较快。但程序员是无法控制的。
        堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

    存储内容
        栈:在栈中,第一个进栈的是主函数下一条指令的地址,然后是函数的各个参数,在大多数编译器中,参数是由右往左入栈,然后是函数中的局部变量。注意,静态变量不入栈。出栈则刚好顺序相反。
        堆:一般在堆的头部用一个字节存放堆的大小,具体内容由程序员安排。

六、性能分析

XDebug
    在php.ini内如下设置
        zend_extension = "D:\xampp\php\ext\php_xdebug.dll"
        xdebug.collect_includes = 1
        xdebug.profiler_enable = 0
        xdebug.profiler_enable_trigger = 1
        xdebug.profiler_output_dir = "D:\xampp\tmp"
        xdebug.profiler_output_name = "cachegrind.out.%u.log"
    配置完毕后重启Nginx,在zf2项目URL中加入XDEBUG_PROFILE即可开启Xdebug Log输出
    参考:https://avnpc.com/pages/how-to-debug-under-zf2

xhprof
    安装xhprof, 修改php.ini,  echo "extension=xhprof.so" > /etc/php5/fpm/conf.d/xhprof.ini
    UI里列出了:
        funciton name : 函数名
        calls: 调用次数
        Incl. Wall Time (microsec): 函数运行时间(包括子函数)
        IWall%:函数运行时间(包括子函数)占比
        Excl. Wall Time(microsec):函数运行时间(不包括子函数)
        EWall%:函数运行时间(不包括子函数)
    注入方式
        1. 直接注入
            //开启xhprof
            xhprof_enable(XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU);
            //在程序结束后收集数据
            register_shutdown_function(function() {
                $xhprof_data = xhprof_disable();

                //让数据收集程序在后台运行
                if (function_exists('fastcgi_finish_request')) {
                    fastcgi_finish_request();
                }

                //保存xhprof数据
                ...
            });

        2.  fpm配置注入
            vi /usr/local/php7/etc/php-fpm.ini
            修改配置:auto_prepend_file = /opt/htdocs/xhgui/external/header.php

        3. Nginx注入
            fastcgi_param PHP_VALUE "auto_prepend_file=/opt/htdocs/xhgui/external/header.php";
posted @ 2018-07-26 11:20  oneVillager  阅读(581)  评论(0编辑  收藏  举报
打赏

喜欢请打赏

扫描二维码打赏