好得很程序员自学网
  • 首页
  • 后端语言
    • C#
    • PHP
    • Python
    • java
    • Golang
    • ASP.NET
  • 前端开发
    • Angular
    • react框架
    • LayUi开发
    • javascript
    • HTML与HTML5
    • CSS与CSS3
    • jQuery
    • Bootstrap
    • NodeJS
    • Vue与小程序技术
    • Photoshop
  • 数据库技术
    • MSSQL
    • MYSQL
    • Redis
    • MongoDB
    • Oracle
    • PostgreSQL
    • Sqlite
    • 数据库基础
    • 数据库排错
  • CMS系统
    • HDHCMS
    • WordPress
    • Dedecms
    • PhpCms
    • 帝国CMS
    • ThinkPHP
    • Discuz
    • ZBlog
    • ECSHOP
  • 高手进阶
    • Android技术
    • 正则表达式
    • 数据结构与算法
  • 系统运维
    • Windows
    • apache
    • 服务器排错
    • 网站安全
    • nginx
    • linux系统
    • MacOS
  • 学习教程
    • 前端脚本教程
    • HTML与CSS 教程
    • 脚本语言教程
    • 数据库教程
    • 应用系统教程
  • 新技术
  • 编程导航
    • 区块链
    • IT资讯
    • 设计灵感
    • 建站资源
    • 开发团队
    • 程序社区
    • 图标图库
    • 图形动效
    • IDE环境
    • 在线工具
    • 调试测试
    • Node开发
    • 游戏框架
    • CSS库
    • Jquery插件
    • Js插件
    • Web框架
    • 移动端框架
    • 模块管理
    • 开发社区
    • 在线课堂
    • 框架类库
    • 项目托管
    • 云服务

当前位置:首页>后端语言>PHP
<tfoot draggable='sEl'></tfoot>

打印PHP堆栈信息 js打印堆栈信息

很多站长朋友们都不太清楚打印PHP堆栈信息,今天小编就来给大家整理打印PHP堆栈信息,希望对各位有所帮助,具体内容如下:

本文目录一览: 1、 怎么让程序异常退出时打印堆栈信息 2、 php怎么获取父函数名 3、 php能不能像java那样打印错误堆栈信息到错误日志 4、 php不打印调用栈 5、 怎么打印php版本信息 6、 如何在进程崩溃后打印堆栈并防止数据丢失 怎么让程序异常退出时打印堆栈信息

打印堆栈是调试的常用方法,一般在系统异常时,我们可以将异常情况下的堆栈打印出来,这样十分方便错误查找。实际上还有另外一个非常有用的功能:分析代码的行为。android代码太过庞大复杂了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要。

Android打印堆栈的方法,简单归类一下

1. zygote的堆栈dump

实际上这个可以同时dump java线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到。

使用方法很简单,直接在adb shell或串口中输入:

[plain] view plaincopy

kill -3 <pid>

输出的trace会保存在 /data/anr/traces.txt文件中。这个需要注意,如果没有 /data/anr/这个目录或/data/anr/traces.txt这个文件,需要手工创建一下,并设置好读写权限。

如果需要在代码中,更容易控制堆栈的输出时机,可以用以下命令获取zygote的core dump:

[java] view plaincopy

Process.sendSignal(pid, Process.SIGNAL_QUIT);

原理和命令行是一样的。

不过需要注意两点:

adb shell可能会没有权限,需要root。

android 4.2中关闭了native thread的堆栈打印,详见 dalvik/vm/Thread.cpp的dumpNativeThread方法:

[cpp] view plaincopy

dvmPrintDebugMessage(target,

"\"%s\" sysTid=%d nice=%d sched=%d/%d cgrp=%s\n",

name, tid, getpriority(PRIO_PROCESS, tid),

schedStats.policy, schedStats.priority, schedStats.group);

dumpSchedStat(target, tid);

// Temporarily disabled collecting native stacks from non-Dalvik

// threads because sometimes they misbehave.

//dvmDumpNativeStack(target, tid);

Native堆栈的打印被关掉了!不过对于大多数情况,可以直接将这个注释打开。

php怎么获取父函数名

函数是没有父子关系的,所以无法获取父函数名。

对象具有父子关系,但是方法名称和父类的方法名称必然是同名的。

另一种可能是你想问谁调用的当前函数,可以打印堆栈信息。print_r(debug_backtrace());

php能不能像java那样打印错误堆栈信息到错误日志

PHP 确实不会输出错误堆栈,但通过函数,还是能够获取到错误堆栈的。

function getBacktrace() {

ob_start();

debug_print_backtrace();

return ob_get_clean();

}

调用上面这个函数取得错误堆栈,再用 file_put_contents('log_path', FILE_APPEND); 写入日志文件即可。

还有一个办法:为 PHP 安装 xdebug 扩展

windows 下的安装方法 安装好后,修改 php.ini

php不打印调用栈

基于以上原因,今天我们就来讲一讲在 PHP 项目当中,怎样快速得到 PHP 调用栈。

PHP 调用栈,顾名思义就是从我们 Web 访问项目的时候,PHP 从执行开始到返回给我们结果的这一系列操作的 PHP 类/方法等调用的过程。

一、利用 XDebug 扩展的 xdebug_get_function_stack() 函数

对 XDebug 扩展了解的同学,可以知道 XDebug 的功能主要用于代码调试。其中,XDebug 就提供了一个非常有用的函数:xdebug_get_function_stack()。

从这个函数的的名字我们可以知道它就是获取方法调用栈的。

我们只需要在项目当中放到 PHP 脚本当中,只要这个方法被执行到。那么,这个方法就能打印 PHP 脚本从开始到执行到这个位置的所有调用栈。从而就能解决我们对代码执行流程不清晰的问题。

这个方法会返回一个数组。数据里面包含了执行的脚本文件路径、类名、方法名、参数等信息。

注:该方法生成的调用栈信息相对比较粗糙。对于简单初浅调试完成够用了。同时,要使用这个方法,必须安装 XDebug 扩展。PHP 安装 XDebug 扩展的教程网上很多。这里不赘述。

二、利用 phptrace 扩展查看

phptrace 是一个追踪(trace)PHP 执行流程的工具。这是奇虎 360 团队开源的一款 PHP 扩展工具。它本身的功能之一就是查看 PHP 调用栈。所以,推荐指数 5 颗星。

项目开源地址:

安装扩展:

$ wget

$ tar zxvf trace-1.0.1beta.tgz

$ cd trace-1.0.1beta/extension

$ {php_bin_dir}/phpize

$ ./configure --with-php-config={php_bin_dir}/php-config

$ make

$ make cli

$ make install-all

然后在 php.ini 配置文件末尾增加:

extension=trace.so

重启我们的 PHP-FPM。

为了能在命令行使用 phptrace 提供的命令,我们还需要在刚刚的 exten

怎么打印php版本信息

Php的版本控制一直也是一个比较棘手的问题,因为版本不同导致有许多功能不能很好的实现,所以当程序上传到空间的时候一定要对版本进行有效的控制,这样可以避免不必要的麻烦产生。那么如何查看当前你的php版本呢?下面提供两种方法帮你查看你的php版本。

使用phpinfo()函数,该函数就是用来显示php服务器的配置信息,在你的环境下创建一个php文件,在里面数据下面代码,然后执行就会打印出下面结果,可以清楚的看到,你当前php的版本,已经php、apache、mysql等配置信息。

<?php

Phpinfo();

?>

使用phpsersion()函数,这个函数的原型是string phpversion(void);返回的一个string,本函数是返回php版本信息,创建一个php文件,输入以下代码,就可以在浏览器中看到返回的php的版本信息了。

<?php

echo phpversion();

?>

如何在进程崩溃后打印堆栈并防止数据丢失

进程在运行过程中遇到逻辑错误, 比如除零, 空指针等等, 系统会触发一个软件中断.

这个中断会以信号的方式通知进程, 这些信号的默认处理方式是结束进程.

发生这种情况, 我们就认为进程崩溃了.

进程崩溃后, 我们会希望知道它是为何崩溃的, 是哪个函数, 哪行代码引起的错误.

另外, 在进程退出前, 我们还希望做一些善后处理, 比如把某些数据存入数据库, 等等.

下面, 我会介绍一些技术来达成这两个目标.

1. 在core文件中查看堆栈信息

如果进程崩溃时, 我们能看到当时的堆栈信息, 就能很快定位到错误的代码.

在 gcc 中加入 -g 选项, 可执行文件中便会包含调试信息. 进程崩溃后, 会生成一个 core 文件.

我们可以用 gdb 查看这个 core 文件, 从而知道进程崩溃时的环境.

在调试阶段, core文件能给我们带来很多便利. 但是在正式环境中, 它有很大的局限:

1. 包含调试信息的可执行文件会很大. 并且运行速度也会大幅降低.

2. 一个 core 文件常常很大, 如果进程频繁崩溃, 硬盘资源会变得很紧张.

所以, 在正式环境中运行的程序, 不会包含调试信息.

它的core文件的大小, 我们会把它设为0, 也就是不会输入core文件.

在这个前提下, 我们如何得到进程的堆栈信息呢?

2. 动态获取线程的堆栈

c 语言提供了 backtrace 函数, 通过这个函数可以动态的获取当前线程的堆栈.

要使用 backtrace 函数, 有两点要求:

1. 程序使用的是 ELF 二进制格式.

2. 程序连接时使用了 -rdynamic 选项.

-rdynamic可用来通知链接器将所有符号添加到动态符号表中, 这些信息比 -g 选项的信息要少得多.

下面是将要用到的函数说明:

#include <execinfo.h>

int backtrace(void **buffer,int size);

用于获取当前线程的调用堆栈, 获取的信息将会被存放在buffer中, 它是一个指针列表。

参数 size 用来指定buffer中可以保存多少个void* 元素。

函数返回值是实际获取的指针个数, 最大不超过size大小

注意: 某些编译器的优化选项对获取正确的调用堆栈有干扰,

另外内联函数没有堆栈框架; 删除框架指针也会导致无法正确解析堆栈内容;

char ** backtrace_symbols (void *const *buffer, int size)

把从backtrace函数获取的信息转化为一个字符串数组.

参数buffer应该是从backtrace函数获取的指针数组,

size是该数组中的元素个数(backtrace的返回值) ;

函数返回值是一个指向字符串数组的指针, 它的大小同buffer相同.

每个字符串包含了一个相对于buffer中对应元素的可打印信息.

它包括函数名,函数的偏移地址, 和实际的返回地址.

该函数的返回值是通过malloc函数申请的空间, 因此调用者必须使用free函数来释放指针.

注意: 如果不能为字符串获取足够的空间, 函数的返回值将会为NULL.

void backtrace_symbols_fd (void *const *buffer, int size, int fd)

与backtrace_symbols 函数具有相同的功能,

不同的是它不会给调用者返回字符串数组, 而是将结果写入文件描述符为fd的文件中,每个函数对应一行.

3. 捕捉信号

我们希望在进程崩溃时打印堆栈, 所以我们需要捕捉到相应的信号. 方法很简单.

#include <signal.h>

void (*signal(int signum,void(* handler)(int)))(int);

或者: typedef void(*sig_t) ( int );

sig_t signal(int signum,sig_t handler);

参数说明:

第一个参数signum指明了所要处理的信号类型,它可以是除了SIGKILL和SIGSTOP外的任何一种信号。

第二个参数handler描述了与信号关联的动作,它可以取以下三种值:

1. 一个返回值为正数的函数的地址, 也就是我们的信号处理函数.

这个函数应有如下形式的定义: int func(int sig); sig是传递给它的唯一参数。

执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。

当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。

2. SIGIGN, 忽略该信号.

3. SIGDFL, 恢复系统对信号的默认处理。

返回值: 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。

注意:

当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,

直到信号处理函数执行完毕再重新调用相应的处理函数。

如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。

在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,

如果要改变此操作请改用sigaction()。

4. 实例

下面我们实际编码, 看看具体如何在捕捉到信号后, 打印进程堆栈, 然后结束进程.

#include <iostream>

#include <time.h>

#include <signal.h>

#include <string.h>

#include <execinfo.h>

#include <fcntl.h>

#include <map>

using namespace std;

map<int, string> SIG_LIST;

#define SET_SIG(sig) SIG_LIST[sig] = #sig;

void SetSigList(){

SIG_LIST.clear();

SET_SIG(SIGILL)//非法指令

SET_SIG(SIGBUS)//总线错误

SET_SIG(SIGFPE)//浮点异常

SET_SIG(SIGABRT)//来自abort函数的终止信号

SET_SIG(SIGSEGV)//无效的存储器引用(段错误)

SET_SIG(SIGPIPE)//向一个没有读用户的管道做写操作

SET_SIG(SIGTERM)//软件终止信号

SET_SIG(SIGSTKFLT)//协处理器上的栈故障

SET_SIG(SIGXFSZ)//文件大小超出限制

SET_SIG(SIGTRAP)//跟踪陷阱

}

string GetSigName(int sig){

return SIG_LIST[sig];

}

void SaveBackTrace(int sig){

//打开文件

time_t tSetTime;

time(tSetTime);

tm* ptm = localtime(tSetTime);

char fname[256] = {0};

sprintf(fname, "core.%d-%d-%d_%d_%d_%d",

ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,

ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

FILE* f = fopen(fname, "a");

if (f == NULL){

exit(1);

}

int fd = fileno(f);

//锁定文件

flock fl;

fl.l_type = F_WRLCK;

fl.l_start = 0;

fl.l_whence = SEEK_SET;

fl.l_len = 0;

fl.l_pid = getpid();

fcntl(fd, F_SETLKW, fl);

//输出程序的绝对路径

char buffer[4096];

memset(buffer, 0, sizeof(buffer));

int count = readlink("/proc/self/exe", buffer, sizeof(buffer));

if(count > 0){

buffer[count] = '\n';

buffer[count + 1] = 0;

fwrite(buffer, 1, count+1, f);

}

//输出信息的时间

memset(buffer, 0, sizeof(buffer));

sprintf(buffer, "Dump Time: %d-%d-%d %d:%d:%d\n",

ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,

ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

fwrite(buffer, 1, strlen(buffer), f);

//线程和信号

sprintf(buffer, "Curr thread: %d, Catch signal:%s\n",

pthread_self(), GetSigName(sig).c_str());

fwrite(buffer, 1, strlen(buffer), f);

//堆栈

void* DumpArray[256];

int nSize = backtrace(DumpArray, 256);

sprintf(buffer, "backtrace rank = %d\n", nSize);

fwrite(buffer, 1, strlen(buffer), f);

if (nSize > 0){

char** symbols = backtrace_symbols(DumpArray, nSize);

if (symbols != NULL){

for (int i=0; i<nSize; i++){

fwrite(symbols[i], 1, strlen(symbols[i]), f);

fwrite("\n", 1, 1, f);

}

free(symbols);

}

}

//文件解锁后关闭, 最后终止进程

fl.l_type = F_UNLCK;

fcntl(fd, F_SETLK, fl);

fclose(f);

exit(1);

}

void SetSigCatchFun(){

map<int, string>::iterator it;

for (it=SIG_LIST.begin(); it!=SIG_LIST.end(); it++){

signal(it->first, SaveBackTrace);

}

}

void Fun(){

int a = 0;

int b = 1 / a;

}

static void* ThreadFun(void* arg){

Fun();

return NULL;

}

int main(){

SetSigList();

SetSigCatchFun();

printf("main thread id = %d\n", (pthread_t)pthread_self());

pthread_t pid;

if (pthread_create(pid, NULL, ThreadFun, NULL)){

exit(1);

}

printf("fun thread id = %d\n", pid);

for(;;){

sleep(1);

}

return 0;

}

文件名为 bt.cpp

编译: g++ bt.cpp -rdynamic -I /usr/local/include -L /usr/local/lib -pthread -o bt

主线程创建了 fun 线程, fun 线程有一个除零错误, 系统抛出 SIGFPE 信号.

该信号使 fun 线程中断, 我们注册的 SaveBackTrace 函数捕获到这个信号, 打印相关信息, 然后终止进程.

在输出的core文件中, 我们可以看到简单的堆栈信息.

5. 善后处理

在上面的例子中, fun 线程被 SIGFPE 中断, 转而执行 SaveBackTrace 函数.

此时, main 线程仍然在正常运行.

如果我们把 SaveBackTrace 函数最后的 exit(1); 替换成 for(;;)sleep(1);

main 线程就可以一直正常的运行下去.

利用这个特点, 我们可以做很多其它事情.

游戏的服务器进程常常有这些线程:

网络线程, 数据库线程, 业务处理线程. 引发逻辑错误的代码常常位于业务处理线程.

而数据库线程由于功能稳定, 逻辑简单, 是十分强壮的.

那么, 如果业务处理线程有逻辑错误, 我们捕捉到信号后, 可以在信号处理函数的最后,

通知数据库线程保存游戏数据.

直到数据库线程把游戏信息全部存入数据库, 信号处理函数才返回.

这样, 服务器宕机不会导致回档, 损失被大大降低.

要实现这个机制, 要求数据库模块和业务处理模块具有低耦合度.

当然, 实际应用的时候, 还有许多细节要考虑.

比如, 业务处理线程正在处理玩家的数据, 由于发生不可预知的错误, 玩家的数据被损坏了, 这些玩家的数据就不应该被存入数据库.

关于打印PHP堆栈信息的介绍到此就结束了,不知道本篇文章是否对您有帮助呢?如果你还想了解更多此类信息,记得收藏关注本站,我们会不定期更新哦。

查看更多关于打印PHP堆栈信息 js打印堆栈信息的详细内容...

声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did210692
更新时间:2023-05-03   阅读:24次

上一篇: php二维数组个数 php二维数组赋值

下一篇:php商标查询系统 商标查询网站数据

相关资讯

最新资料更新

  • 1.imagephp缩放 缩放图像可以改变图像的分辨率吗
  • 2.phpml源码安装 下载了个php源码包,怎么使用
  • 3.php语法基础csdn php语言基础
  • 4.php网站设计素材 php网站制作
  • 5.输出图片php 输出图片英文
  • 6.nginx隐藏.php nginx隐藏ip
  • 7.php用户资料转移 php迁移java
  • 8.php网页打印控件谷歌 php打印插件
  • 9.php项目的更新 php版本升级对程序影响
  • 10.php变量内存溢出 php 内存限制
  • 11.phpmysql框架 php框架yii
  • 12.原生php提交form php原生开发的好处
  • 13.php部署云空间 php云开发
  • 14.php在线直播详解 php直播用的什么技术
  • 15.php图书管理系统 php图书管理系统全部代码
  • 16.包含phpgabage的词条
  • 17.php上传图片木马 php图片上传代码
  • 18.php正则获取图片 php使用正则表达式
  • 19.php获取网页乱码 php网页显示乱码
  • 20.主流php框架比较 php框架排行2020

CopyRight:2016-2025好得很程序员自学网 备案ICP:湘ICP备09009000号-16 http://haodehen.cn
本站资讯不构成任何建议,仅限于个人分享,参考须谨慎!
本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。

网站内容来源于网络分享,如有侵权发邮箱到:kenbest@126.com,收到邮件我们会即时下线处理。
网站框架支持:HDHCMS   51LA统计 百度统计
Copyright © 2018-2025 「好得很程序员自学网」
[ SiteMap ]