热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP程序员常用工具,高级php程序员分享

三连问经常有社区的同学问:“我的PHP程序有没有阻塞,我的PHP程序有没有开启协程(对自己写好的代码表示不自信),我的PHP程序有没有问题”.然后贴出了自己的程序,然后进入了愉快的


三连问

经常有社区的同学问: “我的PHP程序有没有阻塞,我的PHP程序有没有开启协程(对自己写好的代码表示不自信),我的PHP程序有没有问题”.然后贴出了自己的程序,然后进入了愉快的灌水环节,随着时间的流逝,我们并没有形成%ignore_a_1%的解决方法.求人不如求己,我们自己来解决这些问题.

方法论

最近接触到一个牛X的名词-方法论.
引用了百度百科一段名词解释

 

方法论,就是关于人们认识世界、改造世界的方法的理论。
它是人们用什么样的方式、方法来观察事物和处理问题。概括地说,世界观主要解决世界“是什么”的问题,方法论主要解决“怎么办”的问题。
方法论是一种以解决问题为目标的理论体系或系统,通常涉及对问题阶段、任务、工具、方法技巧的论述。方法论会对一系列具体的方法进行分析研究、系统总结并最终提出较为一般性的原则。
方法论也是一个哲学概念。人们关于“世界是什么、怎么样”的根本观点是世界观。用这种观点作指导去认识世界和改造世界,就成了方法论。 方法论是普遍适用于各门具体社会科学并起指导作用的范畴、原则、理论、方法和手段的总和。历史唯物主义的著作中经常提到方法论这个概念。

我们PHP程序员是不是也可以有一个方法,解决一些很容易碰到的基础问题.借这个平台抛砖引玉,希望大家多多指教.
还是引用一个牛X的命题,我是谁,从哪来,到哪去?我们也来扪心三连问

  • 我是谁
  • 我要干啥
  • 干的咋样

我是谁

 

这是一个几千年来无数人探索的问题.

PHP是一个解释型的语言,我们首先要上来看看自己的执行的PHP在哪里,是什么,以免在陌生的机器上一顿操作猛如虎才发现没对上号,比如笔者的机器上装了好多个版本的PHP.不要笑话这个问题,真的有不少人工作几年忽略了这个问题.直到他某一天在这个上面浪费了两小时….(逃

1 $ which php 2 /home/shiguangqi/bin/php 3 $ ll /home/shiguangqi/bin/php 4 lrwxrwxrwx 1 shiguangqi shiguangqi 30 10月 25 12:09 /home/shiguangqi/bin/php -> /usr/local/php-7.2.14//bin/php*

 

PHP安装的版本,加载了什么配置文件,PHP的编译参数是什么,有没有你关注的扩展被加载,加载的配置是什么版本等一系列问题.
比如我这里是把不同版本的PHP对应到自己的目录的一个软连上,自由切换不同版本

1 $ php -v 2 PHP 7.2.14 (cli) (built: Jul 4 2019 11:02:01) ( NTS DEBUG ) 3 Copyright (c) 1997-2018 The PHP Group 4 Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

 

加载什么配置

1 $ php --ini 2 Configuration File (php.ini) Path: /usr/local/php-7.2.14/lib 3 Loaded Configuration File: /usr/local/php-7.2.14/lib/php.ini 4 Scan for additional .ini files in: (none) 5 Additional .ini files parsed: (none)

 

编译参数, 我这个版本是debug版本,默认静态编译了这些模块.

1 $ php -i | grep configure 2 Configure Command => './configure' '--prefix=/usr/local/php-7.2.14' '--with-config-file-path=/usr/local/php-7.2.14/lib' '--with-mysqli=mysqlnd' '--with-jpeg-dir' '--with-png-dir' '--with-iconv-dir' '--with-freetype-dir' '--with-zlib' '--with-mhash' '--with-libxml-dir' '--with-curl' '--with-mcrypt' '--with-gd' '--with-openssl' '--enable-ftp' '--enable-xml' '--enable-bcmath' '--enable-gd-native-ttf' '--enable-mbregex' '--enable-mbstring' '--enable-pcntl' '--enable-sockets' '--enable-fpm' '--enable-soap' '--enable-zip' '--enable-debug'

 

查看PHP扩展相关, 其实可以通过php --help 查看更多的用法.
比如大家常用的

php --ri swoole

 

我要干啥

 

以目标为导向

这一部分对于我们来说最熟悉不过,我们每天干的就是这个事情.
设计服务之前要心中要蓝图,最好把90%的时间用来想,10%的时间用来写.不仅犯错少,而且质量高.
比如我要查询redis,然后写了两个最简单的代码

 1 php  2 $redis = new Redis;  3 $redis->connect("127.0.0.1", 6379);  4 $var = $redis->get("key");  5 var_dump($var);  6 php  7 SwooleRuntime::enableCoroutine();  8 go(function () {  9 $redis = new Redis; 10 $redis->connect("127.0.0.1", 6379); 11 $var = $redis->get("key"); 12 var_dump($var); 13 });

 

然后我们愉快的得出了同样的结果.

干的咋样

 

以目标为导向,以结果为标准.

得出结果很容易,问题是我们干的质量怎么样呢,上面的例子只是类比,大家不要耻笑这两个例子太简单.
strace 将是我们有帮手
我们可以这样,看到核心业务的系统调用

 1 strace -s 1000 php redis.php  2 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3  3 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)  4 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0  5 connect(3, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)  6 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLOUT}])  7 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0  8 fcntl(3, F_SETFL, O_RDWR) = 0  9 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 10 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 11 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) 12 sendto(3, "*2rn$3rnGETrn$3rnkeyrn", 22, MSG_DONTWAIT, NULL, 0) = 22 13 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) 14 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLIN}]) 15 recvfrom(3, "$6rnvalue2rn", 8192, MSG_DONTWAIT, NULL, NULL) = 12 16 write(1, "string(6) "", 11string(6) ") = 11 17 write(1, "value2", 6value2) = 6

 

我们还可以加上一些参数,得到更详细的数据,当前系统调用的消耗的时间和当前时间戳

 1 $ strace -ttt -T -s 1000 php redis.php  2 1572266793.054360 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3 <0.000013>  3 1572266793.054389 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) <0.000007>  4 1572266793.054414 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000008>  5 1572266793.054438 connect(3, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000070>  6 1572266793.054533 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLOUT}]) <0.000008>  7 1572266793.054565 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000008>  8 1572266793.054594 fcntl(3, F_SETFL, O_RDWR) = 0 <0.000006>  9 1572266793.054619 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000008> 10 1572266793.054644 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000007> 11 1572266793.054689 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout) <0.000007> 12 1572266793.054717 sendto(3, "*2rn$3rnGETrn$3rnkeyrn", 22, MSG_DONTWAIT, NULL, 0) = 22 <0.000030> 13 1572266793.054788 poll([{fd=3, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=3, revents=POLLIN}]) <0.000007> 14 1572266793.054816 recvfrom(3, "$", 1, MSG_PEEK, NULL, NULL) = 1 <0.000009> 15 1572266793.054851 poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=3, revents=POLLIN}]) <0.000007> 16 1572266793.054878 recvfrom(3, "$6rnvalue2rn", 8192, MSG_DONTWAIT, NULL, NULL) = 12 <0.000009> 17 1572266793.054923 write(1, "string(6) "", 11string(6) ") = 11 <0.000010> 18 1572266793.054951 write(1, "value2", 6value2) = 6 <0.000009> 19 1572266793.054977 write(1, ""n", 2"

 

我们就可以逐行查看程序系统调用的详情.很容易发现,这个程序是阻塞的,虽然每个系统调用的时间极短.但换个业务,换个依赖可就不是这样.但万变不离其宗.

我们再来看第二个程序,也就是开启协程后的系统调用

 1 1572266985.463011 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 4 <0.000016>  2 1572266985.463048 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) <0.000006>  3 1572266985.463070 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000006>  4 1572266985.463092 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000007>  5 1572266985.463127 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000005>  6 1572266985.463167 connect(4, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000076>  7 1572266985.463296 epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLOUT, {u32=4, u64=38654705668}}) = 0 <0.000011>  8 1572266985.463353 epoll_wait(3, [{EPOLLOUT, {u32=4, u64=38654705668}}], 4096, 60000) = 1 <0.000007>  9 1572266985.463383 epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL) = 0 <0.000008> 10 1572266985.463407 getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000008> 11 1572266985.463445 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000007> 12 1572266985.463467 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000007> 13 1572266985.463525 recvfrom(4, 0x7f29bb9b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000008> 14 1572266985.463556 sendto(4, "*2rn$3rnGETrn$3rnkeyrn", 22, 0, NULL, 0) = 22 <0.000033> 15 1572266985.463633 recvfrom(4, 0x7f29bb9b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000006> 16 1572266985.463662 recvfrom(4, "$6rnvalue2rn", 8192, 0, NULL, NULL) = 12 <0.000007> 17 1572266985.463713 write(1, "string(6) "", 11string(6) ") = 11 <0.000009> 18 1572266985.463740 write(1, "value2", 6value2) = 6 <0.000008>

 

可以发现,通过创建socket,然后connect操作,然后通过epoll_ctl加入监听,是通过多路复用的方式,这里是没有阻塞等待的,我们可以通过这种方式明确的确认自己的程序细节.
比如,可以从第八行看到这里超时等待的时间是60s.
然后我们修改代码超时时间为0.5s

1 php 2 SwooleRuntime::enableCoroutine(); 3 go(function () { 4 $redis = new Redis; 5 $redis->connect("127.0.0.1", 6379, 0.5); 6 $var = $redis->get("key"); 7 var_dump($var); 8 });

 

然后继续查看

 1 1572267648.851924 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 4 <0.000011>  2 1572267648.851952 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) <0.000004>  3 1572267648.851968 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 <0.000004>  4 1572267648.851986 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000005>  5 1572267648.852011 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000006>  6 1572267648.852042 connect(4, {sa_family=AF_INET, sin_port=htons(6379), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000058>  7 1572267648.852131 epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLOUT, {u32=4, u64=38654705668}}) = 0 <0.000006>  8 1572267648.852164 epoll_wait(3, [{EPOLLOUT, {u32=4, u64=38654705668}}], 4096, 500) = 1 <0.000006>  9 1572267648.852184 epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL) = 0 <0.000005> 10 1572267648.852201 getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 <0.000006> 11 1572267648.852225 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000058> 12 1572267648.852302 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [0], 4) = 0 <0.000006> 13 1572267648.852350 recvfrom(4, 0x7f71f91b033d, 1, MSG_PEEK, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000006> 14 1572267648.852373 sendto(4, "*2rn$3rnGETrn$3rnkeyrn", 22, 0, NULL, 0) = 22 <0.000029> 15 1572267648.852446 recvfrom(4, "$", 1, MSG_PEEK, NULL, NULL) = 1 <0.000011> 16 1572267648.852486 recvfrom(4, "$6rnvalue2rn", 8192, 0, NULL, NULL) = 12 <0.000006> 17 1572267648.852523 write(1, "string(6) "", 11string(6) ") = 11 <0.000008> 18 1572267648.852543 write(1, "value2", 6value2) = 6 <0.000006>

 

然后第8行可以发现,超时的时间变为500ms, 这样可以发现一些简单,但是非常重要的细节.同样第一个例子的超时时间也可以阅读到.

运行中的进程可以通过 strace -p pid 来查看详情.
关于strace更详细的用法可以 man strace 来查看.

升华

如果我们的项目很复杂,怎么定位自己运行时问题,阻塞等待时间太长,死循环等问题.其实也是利用strace工具,可以先结合top来查看系统的负载,以及进程占用资源.常见的也就是内存和CPU.
vmstat 也是非常好的工具.
当然也有全自动化的工具,比如swoole tracker深入PHP内核,可以全自动检查阻塞,甚至是内存泄漏.当然也可以自己写脚本来实现.

常用的工具还有gdb,下一篇我们一起来实验gdb工具对PHP程序员的巨大作用.

www.dengb.comtruehttp://www.dengb.com/PHPjc/1380879.htmlTechArticlePHP程序员-常用工具,高级php程序员 三连问 经常有社区的同学问: 我的PHP程序有没有阻塞,我的PHP程序有没有开启协程(对自己写好的代码表…

—-想了解更多的php相关异常处理怎么解决关注<编程笔记>


推荐阅读
  • CentOS8.4 安装PHP7.4.25
    1、下载官网:https:www.php.netdownloads#cdmydata#wgethttps:www.php.netdistributionsphp ... [详细]
  • 导读:今天编程笔记来给各位分享关于php动态扩展怎么加载的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: ... [详细]
  • Linux提权之suid篇
    Linux提权之suid篇不知攻,焉知防一个在安服路上摸索的大三生,记录平时学习笔记suid前言:1.只有可以执行的二进制程序文件才 ... [详细]
  • Logistic回归主要针对输入的数据是多个,输出则是有限的数值型,多为2个分类。涉及到以下方面:1.输出yw0+w1*x1+w2*x2+..(x1,x2,是样本的 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • 下面是一个用openssl实现获取https网页内容的demo,整个流程比较简单,主要封装的API如下staticinthttps_init(http ... [详细]
  • 安全加密C语言库OpenSSL,在Android中服务器和客户端之间的签名验证和数据加密通信等。OpenSSL系列文章:一、AndroidCMake轻松 ... [详细]
  • phpmysql一键安装包,Mysql安装包
    本文目录一览:1、哪里有PHPMySQLDatabaseApacheServer一 ... [详细]
  • 我正在尝试处理来自$datacurl_exec($ch)的结果;而不是在屏幕上打印它.为了实现这一点,我将选项CURLOPT_RETURNTRANSFER设置为true,如下所示: ... [详细]
  • 这里是一些专栏的废话,你可以从下一个分界线开始:)---------------------------------------------------------- ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
author-avatar
路啦Nantale
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有