首页
关于
留言
接口
搜索
首页
登录
登录
搜索
KAKA 梦很美
累计撰写
47
篇文章
累计收到
0
条评论
首页
栏目
首页
登录
页面
首页
关于
留言
接口
PHP
置顶
史上最全 PhpStorm Xdebug 远程连接 Docker 断点调试及单元测试
Why? PHP 程序报错,仔细检查代码后找不到问题。需要重点检查 switch 语句分支判断,确保符合预期。建议使用 Xdebug 断点调试,可以方便地定位错误和查看变量值,帮助快速解决问题。 启用 Xdebug,逐行进入代码,深入了解其执行流程。这将揭示代码的真实运行步骤和调用关系。 此外,Xdebug 可让你实时跟踪每个变量的值和变化,消除 var_dump 代码注入(忘记移除将导致尴尬的代码提交,成为团队耻辱)。 Xdebug 说明 Xdebug 是一个 PHP 扩展,提供调试和性能分析功能。 Xdebug 调试信息, 异常消息中的堆栈和函数调用跟踪 用户定义函数的完整参数列表 函数名称、文件名和行号 对成员函数的支持 内存分配 保护用户免受无限递归的影响 其他功能 PHP 脚本的概要分析信息 代码覆盖率分析 交互式调试脚本的功能,通过调试器前端进行交互 开始使用 Xdebug 扩展安装就不介绍了, 这里假设您已经安装好了。接下来我们就开始配置 PHPStorm: 找到如图所示的位置 或 点击设置->构建、执行、部署->Docker->添加服务, 提示连接成功表示远程连接 Docker 完成 (当然你也可以用 TCP套接字 连接) 连接完成后如下图打开连接的 Docker 服务, 此时已经可以看到 Docker 容器等信息了 接下来配置 PHP-CLI 解析器, 废话少说 如下图 到此, PHP-CLI 解析器已经配置完成。 配置单元测试 (PHPUnit) 直接上图, 按图的步骤操作即可。随便打开一个 Test.php 文件, 配置 PHP 单元测试 (PHPUnit) , 编写测试代码后运行即可。 配置断点调试 配置 php.ini 文件的 Xdebug 参数 这里安装的 Xdebug 版本是 2.9.6 , 如果是 3.0 以上版本的 Xdebug 配置参数会有所不同 (自行谷歌, 稍作修改即可)。 附带一个Jetbrains 官方 的方式 点击查看。 如下是 Xdebug 2.9.6 扩展的配置参数, 打开 php.ini 配置文件: [xdebug] ;开启 Xdebug 支持远程调试 xdebug.remote_enable=1 ;远程调试的主机,一般都是 Docker 宿主机器,本地调试就是本机,IP 可以通过 `docker inspect 容器名` 获得 xdebug.remote_host=host.docker.internal ;远程调试机器的端口,一般是9000 xdebug.remote_port=9000 ;idekey 对接调试的密钥,调试时候和 PhpStorm 里面的务必保持一致 xdebug.idekey=PHPSTORM ;自动触发调试,可以将这个值设为1 xdebug.remote_autostart=1 xdebug.remote_handler="dbgp" ;启用代码自动跟踪 xdebug.auto_trace = On ;启用性能检测分析 xdebug.profiler_enable = On xdebug.profiler_enable_trigger = On xdebug.profiler_output_name = profiler.out.%t.%p 配置完成后重启 php 或 容器 。 配置 PhpStorm, 打开设置按照下图配置 打开项目, 增加远程 Debug 配置 配置浏览器插件 最后安装浏览器插件, 这里用的 Google 浏览器 (如果是其他浏览器也可以通过对应的插件市场查找), 需要到插件市场下载 Xdebug Helper, 如果无法翻墙可以通过下载安装包然后导入即可。 安装完 Xdebug Helper 扩展后, 右键 Xdebug 图标选择选项点击进入配置页面, 配置为如下效果 然后在浏览器中输入即将调试的接口地址,在点击左键 Xdebug 图标,点击 Debug 按钮将 Xdebug 变为绿色 开始调试 第一步: 打开调试按钮, 设置代码断点和选择需要调试的服务 第二步: 点击开始调试按钮 第三步: 打开网站刷新, 将自动跳转至 PhpStorm, 显示如下调试内容 结尾!!! 整个 PhpStorm Xdebug 远程连接 Docker 断点调试及单元测试 教程完成了, 如果觉得本文对您有帮助, 记得点点赞哦~
2024年-2月-28日
223 阅读
0 评论
PHP
2022-10-12
开发PHP扩展
PHP 的底层是由 c/c++ 实现的,所以 PHP 本身就是一层皮,而我们也可以通过开发一些扩展来增强 PHP 的能力。可以通过 php -m 或 phpinfo() 来查看环境中已安装的扩展。这里使用的PHP 版本是 7.4, 为了方便演示 PHP源码文件在 /Users/linshan/Container/C/php-7.4.24, 编译安装的目录为 /Users/linshan/Container/C/php-7.4.24/php74。 生成扩展 进入源码目录下的 ext 目录, 可以看到下面有个 ext_skel.php 文件,该文件是用来生成扩展工程的脚手架命令。 如上命令, 生成名称为 goext 的 PHP 扩展, 在 ext 目录下会生成 goext 文件夹, 该目录下将存放相关扩展的内容。对于 PHP7 是不需要对 php_goext.h 和 goext.c 文件做任何其他变更,可以直接添加自己需要的函数。 打开 goext.c 找一个有利的位置添加以下代码: PHP_FUNCTION(go_version) { php_printf("v1.17"); } 然后找到 static const zend_function_entry goext_functions[] 这行, 将定义的函数添加进来: 到此, PHP 最简单的扩展就已经完成了, go_version 函数的定义在这里的寓意为: 假设用来获取 golang 的版本号。 编译安装 写完了扩展总得检查看看能不能编译吧。接下来我演示下编译安装 goext 扩展。 首先, 进入到 goext 扩展目录。 cd /Users/linshan/Container/C/php-7.4.24/ext/goext 执行 phpize 命令来生成相应的 configure 文件, 已便后续的编译扩展。 /Users/linshan/Container/C/php-7.4.24/php74/bin/phpize 配置安装扩展参数 ./configure --with-php-config=/Users/linshan/Container/C/php-7.4.24/php74/bin/php-config 接下来就是编译安装。 make && make install 如无意外, 您将看到类似下面的界面, 表示编译成功了, PHP 会将 so 文件移动到 PHP 扩展的默认文件路径下。 ini 添加扩展 既然扩展编译安装完成, 那我们就看看能不能加入到 PHP 扩展里并使用吧。 查看下 php.ini 所在的位置。 /Users/linshan/Container/C/php-7.4.24/php74/bin/php -i |grep php.ini 打开 php.ini 文件并加入 goext 扩展。 vi /Users/linshan/Container/C/php-7.4.24/php74/lib/php.ini 检查下 goext 扩展是否安装成功。 /Users/linshan/Container/C/php-7.4.24/php74/bin/php -m // 当然, 您也可以使用命令: /Users/linshan/Container/C/php-7.4.24/php74/bin/php --ri goext 代码调试 简单检查看看能不能调用里面定义的 go_version 函数。 /Users/linshan/Container/C/php-7.4.24/php74/bin/php -r "echo go_version();" 扩展运行成功, 完美输出内容!!!
2022年-10月-12日
179 阅读
0 评论
PHP
2022-8-9
手把手教你源码编译安装PHP及相关扩展
说明 我这边用的是 Mac 操作系统 来演示, 下载的PHP版本 - 7.4.24。 下载、解压 如果你本地有 wget 命令, 可以直接 wget https://www.php.net/distributions/php-7.4.24.tar.gz 当然, 你也可以 点击PHP官网 下载对应的PHP版本源码 下载完之后解压 tar -zxvf php-7.4.24.tar.gz, 为了方便之后需要调试 PHP 的 C 源码, 所以我把 php-7.4.24 文件夹复制放到 /Users/linshan/Container/C 目录下。 配置 PHP 初始的配置和安装过程被 configure 脚本中一系列命令行选项控制。可以通过 ./configure --help 命令了解 PHP 所有可用的编译选项及简短解释。 Linux 下安装软件的步骤: ./configure 执行配置选项(例如 --prefix 可以指定安装位置),判断硬件及操作系统平台,生成 Makefile 文件 make 编译 make install 安装 常用的配置选项 1. PHP 选项 –-prefix[=PREFIX] 安装路径的前缀,可以自定义,例如 /mysoft/php。默认安装在 /usr/local 。 –-with-config-file-path=PATH 设置 php.ini 的搜索路径。默认安装在 PREFIX/lib。 –-disable-short-tags 默认禁用短形式的开始标签 <? 。 --enable-debug 使用调试符号编译。 2. PHP 扩展 –-enable-mbstring 开启 mbstring 多字节扩展 –-with-gd[=DIR] 激活 GD 支持,可以指定扩展位置。编译 GD 库需要libpng 和 libjpeg。 –-with-pear 安装 PEAR 扩展。 –-with-zip[=DIR] 提供 zip 支持,[DIR] 是 ZZIPlib 库安装路径。建议通过 通过 PECL 安装。 --enable-posix 开启 posix 扩展支持。 3. 进程控制扩展 –-enable-pcntl 开启 pcntl 进程控制扩展,只能编译安装。 4. 网络相关扩展 –-with-openssl[=DIR] 开启 OpenSSL 扩展,可以指定扩展位置 –-enable-ftp 开启 FTP 扩展 –-with-curl 支持 cURL –-enable-sockets 开启 socket 扩展 –-enable-soap 支持 SOAP –-enable-fpm 激活 FPM 支持 5. 数据库扩展 –-with-mysql=mysqlnd –-with-mysqli=mysqlnd –-with-pdo-mysql=mysqlnd 运行下配置, 用最简单的配置参数 ./configure --prefix=/Users/linshan/Container/C/php-7.4.24/php74 --enable-debug --enable-mysqlnd --enable-posix --with-iconv=/usr/local/opt/libiconv 在此过程中可能会出现一些报错提示, 根据提示查看相关文档就能解决掉, 这里就不一一说明了。如果一切顺利, 大概会展示下图信息 编译、安装 运行如下命令 make && make install 不出意外, 你会看到如下输出: 此时, 编译安装完成!我们通过 PHP 命令验证下是否安装成功: /Users/linshan/Container/C/php-7.4.24/php74/bin/php -v 源码安装 swoole 扩展 首先下载 swoole 源码, 你也可以到 https://github.com/swoole/swoole-src git 下载 git clone git@github.com:swoole/swoole-src.git 进入 swoole-src 目录 cd swoole-src 通过执行 phpize 命令生成 swoole 安装的 configure 文件 /Users/linshan/Container/C/php-7.4.24/php74/bin/phpize 一切顺利的话, 会生成configure执行文件, 这样就可以配置swoole选项了 接下来配置 swoole ./configure --with-php-config=/Users/linshan/Container/C/php-7.4.24/php74/bin/php-config 编译安装 make && make install 将扩展加入到 php.ini 配置文件, 由于编译安装后并没有设置 php.ini 相关信息, 所以理论上应该是没有该文件的。可以先看看安装在哪个目录 /Users/linshan/Container/C/php-7.4.24/php74/bin/php -i |grep php.ini 然后我们将 /Users/linshan/Container/C/php-7.4.24 目录下的 php.ini-development 或 php.ini-production 配置文件拷贝到 /Users/linshan/Container/C/php-7.4.24/php74/lib 目录下并重命名为 php.ini。 打开 php.ini 文件, 将 swoole 扩展加入到配置中 => extension=swoole.so 。 我们看下是否有安装成功 swoole 扩展 /Users/linshan/Container/C/php-7.4.24/php74/bin/php -m 可以看到是安装成功的, 然后我们可以看看 swoole 相关信息 /Users/linshan/Container/C/php-7.4.24/php74/bin/php --ri swoole 到此, 整个源码编译安装就完成了, 相关的扩展也是类似方式, 安装过程中遇到的环境或软件扩展报错基本都不复杂, 相对容易解决。
2022年-8月-9日
157 阅读
0 评论
PHP
2021-5-6
Swoole 模拟多服务器 Nginx 反向代理实现负载均衡
借用 PHP 的 Swoole 扩展根据不同的端口,启动多个服务器,然后使用 Nginx 反向代理。 如果没有安装 LNMP 开发环境或者没有安装 Swoole 扩展的话可以先查阅为您推荐的文章:CentOS7-4-干净环境配置及搭建LNMP-PHP7 编写服务程序 新建文件 swoole_server1.php <?php $serv = new swoole_http_server("0.0.0.0", 9501); $serv->on('Request', function($request, $response) { $response->cookie("User", "Swoole"); $response->header("X-Server", "Swoole"); $response->end("<meta charset='utf-8'/><h1>Hello Swoole!,你访问的是第一台机器9501</h1>"); }); $serv->start(); 然后复制3份文件 分别命名为: swoole_server2.php swoole_server3.php 和 swoole_server4.php 更改对应的端口和提示语 分别改为 9502、9503和9504 提示语改为 第二台机器 9502、第三台机器 9503 和 第四台机器 9504 配置Nginx反向代理 upstream webswoole { server 127.0.0.1:9501 weight=20; server 127.0.0.1:9502 weight=40; server 127.0.0.1:9503 weight=30; server 127.0.0.1:9504 weight=10; } server { listen 9500; server_name 127.0.0.1; location / { proxy_pass http://webswoole; } } 上面,我使用的是 9500 端口反向代理到四个不同的服务器端口。 启动服务 分别打开4个端口,使用命令 php swoole_server1.php php swoole_server2.php php swoole_server3.php php swoole_server4.php 重启nginx nginx -s reload 访问应用 (curl或打开浏览器网页) curl 127.0.0.1:9500 不断刷新会返回不同的服务器,为了看的更清楚,我写了一个测试 Shell 脚本 test.sh #!/bin/bash for ((i=1; i<=20; i++)) do curl 'http://127.0.0.1:9500/' echo '' sleep 1 done 然后执行脚本,我们看到访问的很均匀的出现了, 你也可以采用其他算法模式把流量分发到想要的服务器。 至此,Swoole 模拟负载均衡的测试完成, 如果是多台真实服务器的话直接替换 upstream 里的地址就可以了。
2021年-5月-6日
185 阅读
0 评论
PHP
2020-3-30
PHP 垃圾回收机制
机制介绍 PHP 使用了引用计数(reference counting)GC机制,同时使用根缓冲区机制,当php发现有存在循环引用的zval时,就会把其投入到根缓冲区,当根缓冲区达到配置文件中的指定数量后,就会进行垃圾回收,以此解决循环引用导致的内存泄漏问题。 循环引用造成的内存泄漏, 我们为了清理这些垃圾,引入了两个准则: 如果引用计数减少到零,所在变量容器将被清除(free),不属于垃圾 如果一个zval的引用计数减少后还大于0,那么它会进入垃圾周期。其次,在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾 每个对象都内含一个引用计数器 refcount,每个reference连接到对象,计数器加1。当reference离开生存空间或被设为 NULL,计数器减1。当某个对象的引用计数器为零时,PHP知道你将不再需要使用这个对象,释放其所占的内存空间。 GC处理完整流程图 机制概念 垃圾回收是一个多数编程语言中都带有的内存管理机制。与非托管性语言相反:C、 C++ 和 Objective C,用户需要手动收集内存,带有 GC 机制的语言:Java、 javaScript 和 PHP 可以自动管理内存。 垃圾回收机制(gc)顾名思义,就是废物重利用的意思,是一种动态存储分配的方案。它会自动释放程序不再需要的已分配的内存块。垃圾回收机制可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻辑。 在现在的流行各种语言当中,垃圾回收机制是新一代语言所共有的特征,如Python、PHP、C#、Ruby 等都使用了垃圾回收机制。 回收原理 在PHP5.3版本之前,使用的垃圾回收机制是单纯的“引用计数”。 什么叫做引用计数? 由于PHP是用C来写的,C里面有一种东西叫做结构体,我们PHP的变量在C中就是用这种方式存储的。 每个PHP的变量都存在于一个叫做zval容器中,一个zval容器,除了包含变量名和值,还包括两个字节的额外信息: ● 一个叫做is_ref,是个布尔值,用来表示这个变量是否属于引用集合,通过这个字节,我们php才能把普通变量和引用变量区分开来。 ● 第二个额外字节就是refcount,用来表示指向这个容器的变量的个数。 怎么理解呢? 即: ① 每个内存对象都分配一个计数器,当内存对象被变量引用时,计数器+1 ② 当变量引用撤掉后(执行 unset 后),计数器-1 ③ 当计数器=0时,表明内存对象没有被使用,该内存对象则进行销毁,垃圾回收完成 并且PHP在一个生命周期结束后就会释放此进程/线程所占的内容,这种方式决定了PHP在前期不需要过多考虑内存的泄露问题。 但是当两个或多个对象互相引用形成环状后,内存对象的计数器则不会消减为0;这时候,这一组内存对象已经没用了,但是不能回收,从而导致内存泄露的现象。 php5.3开始,使用了新的垃圾回收机制,在引用计数基础上,实现了一种复杂的算法,来检测内存对象中引用环的存在,以避免内存泄露。 随着PHP的发展,PHP开发者的增加以及其所承载的业务范围的扩大,在PHP5.3中引入了更加完善的垃圾回收机制,新的垃圾回收机制解决了无法处理循环的引用内存泄漏问题。 官方文档所说,可以使用Xdebug来检查引用计数情况: <?php $a = "new string"; $c = $b = $a; xdebug_debug_zval( 'a' ); unset( $b, $c ); xdebug_debug_zval( 'a' ); // 以上例程会输出: /** * a: (refcount=3, is_ref=0)='new string' * a: (refcount=1, is_ref=0)='new string' **/ 注意:从PHP7的NTS版本开始,以上例子的引用将不再被计数,即$c=$b=$a之后a的引用计数也是,具体分类如下 在PHP7中,zval可以被引用计数或不被引用。在zval结构中有一个标志确定了这一点 ① 对于null,bool,int和double的类型变量,refcount 永远不会计数 ② 对于对象、资源类型,refcount计数和php5的一致 ③ 对于字符串,未被引用的变量被称为“实际字符串”。而那些被引用的字符串被重复删除(即只有一个带有特定内容的被插入的字符串)并保证在请求的整个持续时间内存在,所以不需要为它们使用引用计数;如果使用了opcache,这些字符串将存在于共享内存中,在这种情况下,您不能使用引用计数(因为我们的引用计数机制是非原子的) ④ 对于数组,未引用的变量被称为“不可变数组”。其数组本身计数与php5一致,但是数组里面的每个键值对的计数,则按前面三条的规则(即如果是字符串也不在计数);如果使用opcache,则代码中的常量数组文字将被转换为不可变数组 再次,这些生活在共享内存,因此不能使用 refcounting。 让我们看下例子来理解吧 <?php echo '测试字符串引用计数'; $a = "new string"; $b = $a; xdebug_debug_zval( 'a' ); unset( $b); xdebug_debug_zval( 'a' ); $b = &$a; xdebug_debug_zval( 'a' ); echo '测试数组引用计数'; $c = array('a','b'); xdebug_debug_zval( 'c' ); $d = $c; xdebug_debug_zval( 'c' ); $c[2]='c'; xdebug_debug_zval( 'c' ); echo '测试int型计数'; $e = 1; xdebug_debug_zval( 'e' ); 输出如下: 回收周期 默认的,PHP的垃圾回收机制是打开的,然后有个 php.ini 设置允许你修改它:zend.enable_gc 。 当垃圾回收机制打开时,算法会判断每当根缓存区存满时,就会执行循环查找。根缓存区有固定的大小,默认10,000,可以通过修改PHP源码文件 Zend/zend_gc.c 中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新编译PHP,来修改这个值。当垃圾回收机制关闭时,循环查找算法永不执行,然而,根将一直存在根缓冲区中,不管在配置中垃圾回收机制是否激活。 除了修改配置 zend.enable_gc ,也能通过分别调用 gc_enable() 和 gc_disable()函数在运行PHP时来打开和关闭垃圾回收机制。调用这些函数,与修改配置项来打开或关闭垃圾回收机制的效果是一样的。即使在可能根缓冲区还没满时,也能强制执行周期回收。你能调用 gc_collect_cycles() 函数达到这个目的。这个函数将返回使用这个算法回收的周期数。 允许打开和关闭垃圾回收机制并且允许自主的初始化的原因,是由于你的应用程序的某部分可能是高时效性的。在这种情况下,你可能不想使用垃圾回收机制。当然,对你的应用程序的某部分关闭垃圾回收机制,是在冒着可能内存泄漏的风险,因为一些可能根也许存不进有限的根缓冲区。 因此,就在你调用 gc_disable() 函数释放内存之前,先调用 gc_collect_cycles() 函数可能比较明智。因为这将清除已存放在根缓冲区中的所有可能根,然后在垃圾回收机制被关闭时,可留下空缓冲区以有更多空间存储可能根。 性能影响 内存占用空间的节省 首先,实现垃圾回收机制的整个原因是为了一旦先决条件满足,通过清理循环引用的变量来节省内存占用。在PHP执行中,一旦根缓冲区满了或者调用 gc_collect_cycles() 函数时,就会执行垃圾回收。 执行时间增加 垃圾回收影响性能的第二个领域是它释放已泄漏的内存耗费的时间。 通常,PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中根本就没有性能影响。 在平常脚本中有循环回收机制运行的情况下,内存的节省将允许更多这种脚本同时运行在你的服务器上。因为总共使用的内存没达到上限 这种好处在长时间运行脚本中尤其明显,诸如长时间的测试套件或者daemon脚本此类。同时,对通常比Web脚本运行时间长的脚本应用程序,新的垃圾回收机制,应该会大大改变一直以来认为内存泄漏问题难以解决的看法。 小结 unset : 只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数减1,内存是否回收主要还是看refcount是否到0了 null : 将 null 赋值给一个变量是直接将该变量指向的数据结构置空,同时将其引用计数归0 脚本执行结束 : 该脚本中所有内存都会被释放,无论是否有环引用
2020年-3月-30日
142 阅读
0 评论
PHP