当前位置: 首页 > 编程日记 > 正文

跨平台PHP调试器设计及使用方法——拾遗

之前七篇博文讲解了跨平台PHP调试器从立项到实现的整个过程,并讲解了其使用方法。但是它们并不能全部涵盖所有重要内容,所以新开一片博文,用来讲述其中一些杂项。(转载请指明出于breaksoftware的csdn博客)

触发调试的方法

Xdebug提供了两种调试方式。一种需要我们在触发调试的URL中新增XDEBUG_SESSION_START或XDEBUG_SESSION_STOP_NO_EXEC来控制调试开启或关闭。比如我们要调试http://192.168.41.130/var/www/html/index.php触发的逻辑,则需要请求

http://192.168.41.130/var/www/html/index.php?XDEBUG_SESSION_START=netbeans-xdebug

调试结束后,我们需要请求下面链接以关闭调试

http://192.168.41.130/var/www/html/index.php?XDEBUG_SESSION_STOP_NO_EXEC=netbeans-xdebug

这种方法存在明显的缺陷。比如我们一个待测功能页中,我们不可能给每个触发调试的URL增加上述标志。更不可能在每次调试后触发一次关闭调试的请求。因为页面中发起请求的方式和位置可能很多,每次手工去修改原始代码也违背了我设计该调试器的初衷。我曾考虑过给待测页面包一层框架,即我们设计一个页面“浏览器”。在这个页面浏览器中访问待测页面。待测页面中触发的请求被外层的页面“浏览器”捕获,并追加相关参数再发起真实请求。但是我觉得这个方案有点让整个调试器的设计偏向于设计一款功能强大的页面“浏览器”,所以它只能作为我最次方案的一种选择。

Xdebug还有另一种触发调试的方法,就是自动触发,即每次请求来都触发调试行为。我们需要做的就是在配置文件中新增如下内容

xdebug.remote_autostart=On

这个方案也会有问题。就是我们在调试时往往只是关注于一两个请求对应的处理逻辑,而往往抵达触发这一两个请求场景之前还会有其他请求被发起。打个比方,我们要调试让用户修改自己信息的接口。在此之前肯定有一次获取该用户已有信息的请求,然后把用户信息显示出来。用户修改时,可能有些信息还要经过PHP逻辑校验,这些也是请求。这样在用户保存修改信息之前已经调用了若干接口,而这些接口可能会被我们设置的断点中断。即使我们没有设置断点,也会被中断到代码的第一行。对于这些我们不关心的调试流程,我们可能会不停执行Run当本次调试结束。但是这么繁琐的体验是非常不好的。于是这就有了设计“调试开关”的必要。

在我们触发调试前,我们调试开关关闭,这样既省事又有效率。当我们要触发调试时,才开启调试开关。

Python错误

在一些环境下,使用Python2.7搭建和使用该调试器时,会报CTYPE= CTYPE.ENCODE(DEFAULT_ENCODING) # OMIT IN 3.X! UNICODEDECODEERROR错误。好在网上有很多解决方案,就直接删掉那几行就行。

FPM超时问题

在一些生产环境下,为了增强用户体验以及预防一些错误发生,往往会设置一些超时参数。比如PHP的FPM就可以设置超时时间。但是在开发环境下,一般这个超时可以不用设置,而且设置还会影响调试器的使用。因为我们调试一段代码可能会消耗很多时间,没谁可以估算出这个超时要设置多久。如果遇到这个问题的同学,可能参见《PHP超时处理全面总结》。

Pydbgp的缺陷

在探索Pydbgp库时,我发现这个库并非非常完善,它还存在一些缺陷。同时为了不影响它的整体结构,我基本就是打patch的思路去做修改,且要求做到最小修改以解决问题。

已结束调试Session残留

首先我们使用session查看可调试会话ID,然后使用select指令进入调试会话并进行调试。当我们退出调试会话时,存在两种状态:调试已经结束(运行到代码结尾处之后)和调试仍可进行(只是退出调试会话,该会话还有效)。Pydbgp库存在一个问题,它会一直保存会话ID,而不管其是否已经失效。这样随着我们调试次数的增多,session指令获取的会话ID会越来越多,而往往大部分都是无效的。对于我们自动选择调试会话的调试器状态机来说这个工作任务会越来越重,所以这个地方需要做优化。优化的方案也非常简单,在pydbgpd.py的do_quit方法做如下修改

    def do_quit(self, argv):"""quit, exit, q -- exit the DBGP Application Layer shell"""if self._app.currentSession._stop:self._app.currentSession._application.releaseSession(self._app.currentSession)

当前会话设置出错

在调试器中,有若干会话,其中只有一个会话可能成为当前正在被调试的会话。但是原代码中对当前会话的切换判断存在缺陷,它没有考虑到当前会话是否已经失效。修改点是dbgp\server.py文件中class application的addSession方法

未返回断点ID信息

当我们设置一个断点后,应该返回该断点ID。我们可以通过该断点ID去删除它。然而Pydbgp却将这个ID给“私吞”了。于是我们要做修改让它放开这个数据。修改点在dbgp\server.py文件中

未返回Array和Object类型变量信息

这个问题也是非常致命的。我们查看一个变量,它可能是int型的,可能是string型的。这些基础类型Pydbgp均作了解析和记录。然而对于复杂类型,比如Array或者Object类型变量,Pydbgp都没对它们进行解析。这块功能只能我们自己写了,我决定使用Json格式来保存这些数据。这块的修改点在dbgp\server.py文件中class property的initWithNode函数

还要新增一个转换成Json的函数

父子(孙)进程管理

在我初步的设想中,我们只要让调试器的Python代码在一个进程中执行,然后以其为父进程,启动一个执行Pydbgp库的python子进程进程。这样两个进程之间关系比较简单且易于维护。当我们需要关闭调试时,只要把子进程关闭即可。但是实际实现这段逻辑时,发现Windows上可以做到,但是在我的linux环境则不可以。于是只能靠孙子进程来完成这样的设计。这块代码在class pydbgpd_stub中

    def start(self):if (self._exc_cmd == None):raise NameError("exc_cmd is none")if "Windows" == platform.system():self._process = subprocess.Popen(self._exc_cmd, shell = False)else:self._process = subprocess.Popen(self._exc_cmd, shell = True,  preexec_fn = os.setpgrp)time.sleep(2)self._cmd_client.Start()def stop(self):self._cmd_client.Stop()if not self._process:raise NameError("subprocess is none")else:if "Windows" != platform.system():pid = self._process.pidpgid = os.getpgid(pid)os.kill(-pgid, 9)self._process.terminate()self._process.kill()self._process = None

至此,我们便将该调试器相关设计和使用方法讲完了。代码维护在https://github.com/f304646673/PhpDebugger.git上。

相关文章:

召唤超参调优开源新神器:集XGBoost、TensorFlow、PyTorch、MXNet等十大模块于一身...

整理 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】Optuna是一款为机器学习任务设计的自动超参数优化软件框架,是一款按运行定义(define-by-run) 原则设计的优化软件,允许用户动态地调整搜索空间&#…

Linux下的Silverlight:Moonlight 1.0 Beta 1发布了

Moonlight是微软Silverlight的一个开源实现,其目标平台是Linux与Unix/X11系统。自从2007年9月开始,Moonlight就在Mono项目下进行了开发,它是由Novell发起并资助的。现在,Moonlight 1.0 Beta 1已经向公众发布了。 Novell和Mono宣布…

在visual studio 2010中调用ffmpeg

转自:http://blog.sina.com.cn/s/blog_4178f4bf01018wqh.html 最近几天一直在折腾ffmpeg,在网上也查了许多资料,费了不少劲,现在在这里和大家分享一下。 一、准备工作本来是想自己在windows下编译ffmpeg生成lib、dll等库文件的&am…

无线路由器与无线AP的区别

摆脱线缆的羁绊,手捧一杯香醇的咖啡在家中的任何角落都可以无拘无束和网友谈天说地──这就是无线的魅力!在无线网络迅猛发展的今天,无线局域网(Wireless Local-Area Network,简称WLAN)已经成为许多SOHO家庭…

Simple Dynamic Strings(SDS)源码解析和使用说明一

SDS是Redis源码中一个独立的字符串管理库。它是由Redis作者Antirez设计和维护的。一开始,SDS只是Antirez为日常开发而实现的一套字符串库,它被使用在Redis、Disque和Hiredis等作者维护的项目中。但是作者觉得这块功能还是比较独立的,应该让其…

“不会Linux,到底有多危险?”骨灰级成程序员:基本等于自废武功!

说起程序员的必备技能,我想大家都可以说很多,比如:算法、数据结构、数学、编程语言等等。对于程序员来讲,这些底层能力固然重要,但是,工具同样也是如此,比如常被大家所忽视的:Linux。…

“Uncaught TypeError: string is not a function”

http://www.cnblogs.com/haitao-fan/archive/2013/11/08/3414678.html 今天在js中写了一个方法叫做search(),然后点击按钮的时候提示: “Uncaught TypeError: string is not a function” 百思不得其解啊,我的js木有问题啊啊.... 后来才发现酱…

关于Nikon Ai AF 28mm F1.4D遮光罩的问题

-- 好不容易找到百变妖,确实比较妖!!遮光罩不好找,原厂推荐的HK-7基本属于古董中的古董。 爬文很久,终于找到一篇国外的介绍,说可以用HK-4代替,比HK-7效果更好,而且可以用85mm 1.4D-…

Simple Dynamic Strings(SDS)源码解析和使用说明二

在《Simple Dynamic Strings(SDS)源码解析和使用说明一》文中,我们分析了SDS库中数据的基本结构和创建、释放等方法。本文将介绍其一些其他方法及实现。(转载请指明出于breaksoftware的csdn博客) 字符串连接 SDS库提供下面两种方法进行字符串…

亚马逊机器学习服务:深入研究AWS SageMaker

作者 | Manish Manalath译者 | Shawn编辑 | Carol出品 | AI科技大本营(ID: rgznai100) 机器学习是一个从数据中发现模式的强大概念。但是,如果您尝试过从零开始构建机器模型,那么您一定知道设计一个可扩展的机器学习工作流是多大的…

Java Timer 定时器的使用

一、延时执行首先,我们定义一个类,给它取个名字叫TimeTask,我们的定时任务,就在这个类的main函数里执行。 代码如下:package test;import java.util.Timer;public class TimeTaskTest { public static void main(Str…

Redis源码解析——前言

今天开启Redis源码的阅读之旅。对于一些没有接触过开源代码分析的同学来说,可能这是一件很麻烦的事。但是我总觉得做一件事,不管有多大多难,我们首先要在战略上蔑视它,但是要在战术上重视它。除了一些高大上的技术,我们…

asp.net客户端脚本验证小技巧

通用的客户端脚本验证 Code//验证客户端function checkclient() { var list document.all; for(var i0 ;i<list.length; i) { var h list[i].hint; if(h ! null && h ! "") { if(list[i].isdrop"…

5个可以帮助你提高工作效率的新AI工具

作者 | Kyrylo Lyzanets译者 | 火火酱编辑 | Carol出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09; 毫无意义的新闻、故事和活动会占用你每天多少的工作时间&#xff1f;假如你是一名需要高绩效的高管或专业人士&#xff0c;如果在工作中可以不分心&#xff0c;那你…

Centos6.5更换163源 epel源

想必大家都遇到过&#xff0c;安装新的centos系统&#xff0c;使用yum去安装软件的时候&#xff0c;要么找不到&#xff0c;要么慢的让人发疯。网上其实办法很多&#xff0c;直接更换163源就ok&#xff0c;但是基本所有的文章都是直接wget下163的源&#xff0c;但是不知道为什么…

图模型+Bert香不香?完全基于注意力机制的图表征学习模型Graph-Bert

作者 | Jiawei Zhang、Haopeng Zhang、Congying Xia、Li Sun译者 | 凯隐编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】本文提出了一种全新的图神经网络 Graph-Bert&#xff0c;仅仅基于 Attention 机制而不依赖任何类卷积或聚合操作…

闭关纪要17.Google app engine的简单应用

在上面用了十一篇博客的文章详细的介绍了&#xff0c;Step1账户登录系统之后&#xff0c;从现在开始&#xff0c;继续写闭关纪要&#xff0c;因为Step1账户登录系统也是闭关工作的一部分&#xff0c;因此保留序号&#xff0c;这篇纪要在上次的闭关纪要5.WML,UTF-8,BOM,签名及其…

Redis源码解析——内存管理

在《Redis源码解析——源码工程结构》一文中&#xff0c;我们介绍了Redis可能会根据环境或用户指定选择不同的内存管理库。在linux系统中&#xff0c;Redis默认使用jemalloc库。当然用户可以指定使用tcmalloc或者libc的原生内存管理库。本文介绍的内容是在这些库的基础上&#…

poj_2479 动态规划

题目大意 给定一列数&#xff0c;从中选择两个不相交的连续子段&#xff0c;求这两个连续子段和的最大值。 题目分析 典型的M子段和的问题&#xff0c;使用动态规划的方法来解决。 f[i][j] 表示将A[1...i] 划分为j个不相交连续子串&#xff0c;且A[j]属于第i个子串&#xff0c;…

Redis源码解析——字典结构

C语言中有标准的字典库&#xff0c;我们可以通过pair(key,value)的形式存储数据。但是C语言中没有这种的库&#xff0c;于是就需要自己实现。本文讲解的就是Redis源码中的字典库的实现方法。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 一般情况下&#xf…

十步,教你把Python运行速度提升 30%

作者 | Martin Heinz译者 | 陆离编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】一直以来&#xff0c;诟病 Python语言的人经常说&#xff0c;他们不想使用的一个原因是 Python 的速度太慢了。不管使用哪一种编程语言&#xff0c;程序…

字符串转换成NSDate类型的 为nil解决方法

方法一 通过下列函数来解决 但是得到的日期会改变 修改方法fix- (NSDate *)timeForString:(NSString *)string {NSMutableString *timeString [[NSMutableString alloc] initWithString:string]; [timeString setString:[timeString stringByReplacingOccurrence…

Redis源码解析——字典基本操作

有了《Redis源码解析——字典结构》的基础&#xff0c;我们便可以对dict的实现进行展开分析。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 创建字典 一般字典创建时&#xff0c;都是没有数据的&#xff0c;但是字典类型需要确定&#xff0c;所以我们看到R…

[转]控制 Cookie 的作用范围

默认时&#xff0c;网站的所有 Cookies 都一起被存储在客户端&#xff0c;并且所有 Cookies 连同网站的任何请求一起被发送到服务器。换句话说&#xff0c;网站中的每个页面都能够为网站获取所有的 Cookies。但是&#xff0c;你能够通过两个方式来设置 Cookies 的作用范围&…

强化学习70年演进:从精确动态规划到基于模型

作者 | Nathan Lambert译者 | 泓礼编辑 | 夕颜出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;【导读】这是一份帮你了解强化学习算法本质的资源&#xff0c;无需浏览大量文档&#xff0c;没有一条公式&#xff0c;非常适合学生和研究人员阅读。作为强化学习研究人员…

Android ActionBar相关

1.Android 5.0 删除ActionBar下面的阴影 于Android 5.0假设你发现的ActionBar下面出现了阴影&#xff0c;例如&#xff0c;下面的设置&#xff0c;以消除阴影&#xff1a; getActionBar().setElevation(0); Android 5.0之前能够用以下代码消除阴影&#xff1a; <item name&q…

Redis源码解析——字典遍历

之前两篇博文讲解了字典库的基础&#xff0c;本文将讲解其遍历操作。之所以将遍历操作独立成一文来讲&#xff0c;是因为其中的内容和之前的基本操作还是有区别的。特别是高级遍历一节介绍的内容&#xff0c;充满了精妙设计的算法智慧。&#xff08;转载请指明出于breaksoftwar…

开发者在行动!中国防疫开源项目登上GitHub TOP榜

整理 | 唐小引出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;【导读】用开发者们的方式支援这场没有硝烟的战争&#xff01;截止北京时间 1 月 28 日下午 15:47&#xff0c;全国确诊新型冠状病毒的数字已经到达了 4586 例&#xff0c;疑似高达 6973 例&#xff0c…

像童话一样学习OSPF原理

可以把整个网络&#xff08;一个自治系统AS&#xff09;看成一个王国&#xff0c;这个王国可以分成几个 区(area)&#xff0c;现在我们来看看区域内的某一个人(你所在的机器root)是怎样得到一张 世界地图(routing table)的。   首先&#xff0c;你得跟你周围的人&#xff08;…

队列——PowerShell版

继续读啊哈磊《啊哈&#xff01;算法》感悟系列——队列 地铁售票处排队&#xff0c;先来的人先到队首先买完先走&#xff0c;后来的人排在队尾等候后买完后走。 想买票&#xff0c;必须排在队尾&#xff1b;买完票&#xff0c;只能从队首离开。 这种先进先出&#xff08;First…