当前位置: 首页 > 科技观察

PPython:PHP拥抱Python的利器

时间:2023-03-23 10:44:19 科技观察

简介Python和PHP都是应用广泛的语言,各有千秋。期待两者的结合能够实现更丰富的效果。在PHP中调用Python实现一些处理,虽然这个需求比较小,但是还是很实用的。目前网上可以查到很多资料,还在讨论exec()(包括system()、shell_exec()、passthru()等)来执行外部Python文件,但这只是一般的方法,通话费用相对较高。每次调用时,都需要加载整个Python解释环境。有这种需求的开发者很适合看一看PPython,这是一种本质上将PHP和Python有效结合的技术。PPython最初见于https://code.google.com/p/ppython,作者将lajp(一种PHP-Java技术)移植到Python。项目最初成立于2012年,貌似已经停止维护很多年了,但是其思路和效果还是值得肯定的,所以项目从已经停止的GoogleCode迁移到了GitHub,并且沿用了原来的Apachelicense.发布和维护。笔者前几天对此做了一些尝试,对PPython的便捷易用性有了一些体会。原理和体系结构PHP和Python通信有两种不同的套接字机制:TCP套接字和UNIX套接字。UNIX套接字是Unix/Linux本地套接字。与TCP套接字相比,具有以下特点:只能在同一主机(IPC)内通信,不能跨主机;传输速度高于TCPsocket;只为本机提供服务(无对外监听端口),相对安全,易于管理。PHP和Python各自在语言中定义了自己的数据类型。通常,PHP进程与Python进程交互时,需要进行转码。如果这种转换由应用程序自己实现,那么从开发效率到运行性能都会增加很多额外的负担。PPython支持PHP和Python通信的两种机制,TCPsocket和UNIXsocket,兼顾通信效率和分布,转码由服务统一处理,Python为PHP数据类型提供格式兼容,PHP端开发不需要担心底层通信。由于Python的语言GIL特性,同进程多线程效率不高。PPython可以根据项目需求部署服务,多进程运行Python,提升整体应用性能。使用PPython的代码可以从上面提到的项目库中下载。下载的文件中,以下三个是PPython的核心代码,它们的作用如下:php_python.py,Python进程的主文件,完成Python端的监听请求,返回process.py,Python端核心类,实现Python内部流程调用和PHP与Python数据结构转换等Key处理php_python.php,PPython客户端,PHP端引用该文件,可以直接使用PPython函数实现调用。将以上文件放在任意目录下。首先修改PPython要运行的端口,监听端口不限,只要php_python.py和php_python.php两端修改一致即可。作者统一改为10240。运行当前目录下的php_python.py,只要Python环境正常,就会运行一个PPython服务。------------------------------------------PPython服务-时间:2019-05-1322:24:09---------------------------------------------Listenport:10240charset:utf-8Serverstartup...在PHP端引入php_python.php,就可以使用ppython函数与之前启动的PPython服务通信。传入的请求由PPython服务处理后返回给Python,比如$res=ppython('test::go')就是调用test.py中的go函数,也可以加入更多的参数。第二个参数将更多的参数传递给被调用的函数。php_python.py是PPython启动后直接运行的全局代码。任何全局配置或者进程启动后的一般处理都写在这里。比如在native代码中建立数据库连接等,应该在项目中根据情况进行优化。但Python主要有趣的方面并不只是像PHP那样描述业务功能,它可以为人工智能等领域所需的计算任务提供更复杂数据结构的处理,所以两者的结合可以给PHP带来更多的应用场景。改进此外,本机php_python.py有一些不足之处。笔者在使用ppython调用自定义代码时遇到了三个问题,并相应解决了:不支持Complex(复数类)。复数是数学中的一种数据类型,主要包括real(实部)和imag(虚部))数据,虽然日常生活中遇到的比较少,但AI和各个专业研究领域可能并不少见。Python中有一个complex类,可以直接对复数进行各种计算,但是PPython的序列化和反序列化不处理complex。为了使复杂包含的数据正常返回,只需在process.py的z_encode()方法中加入符合PHP要求的序列化处理即可,代码如下:elifisinstance(p,numpy.complex128):t1=str(p.real)t2=str(p.imag)return'O:7:"complex":2:{s:4:"real";d:%s;s:4:"imag";d:%s;}'%(t1,t2)不支持ndarray(多维数组)。与复杂相比,ndarray更为常见。相信在使用Python的各种计算功能时,都少不了ndarray,甚至ndarray在一定程度上实现了Python。但是原来的php_python.py不识别ndarray。不过,解决起来并不难。在process.py中找到z_encode()方法,添加下面这段,直接将ndarray转成符合PHP要求的数组(数字索引)。elifisinstance(p,numpy.ndarray):s=''i=0fordinp:s+='i:%d;%s'%(i,z_encode(d))i+=1return"a:%d:{%s}"%(len(p),s)原代码不是很健壮,如果数据是ndarray类型,如果p==None:ErrorValueError:Thetruthvalueofanarraywithmore不止一个元素是模棱两可的。使用a.any()或a.all(),因为p==None的结果也是一个ndarray,不会返回false。将判断方式改为ifpisNone:,避免出错。相应的,PHP端也要注意序列化和反序列化的处理。在回复中处理complex之类的对象数据时,如果系统中没有定义对应的类,PHP可以反序列化,但是会显示为“incompleteobject”,vardump可以看到real和imag数据,但是不能直接操作,自己定义复杂类后,会根据指定的类进行解析,与PHP中的一般对象无异,一切操作都可以轻松进行。至此,PHP和Python的功能协调没有问题。补充:注册为服务在命令行下启动php_python.py主要是为了调试,可以看到观察反馈信息等,毕竟在生产环境中手动启动PPython并不方便。PPython可以配置为一个服务,可以修改端口,为不同的应用配置不同的PPython端口。Linux下将进程注册为服务非常简单,只需要创建/usr/lib/systemd/system/ppython.service,内容如下:[Unit]Description=PHP-PythonServiceAfter=network.targetremote-fs.targetnss-lookup.target[Service]ExecStart={PPYTHON_PATH}/php_python.py[Install]WantedBy=multi-user.target其中{PPYTHON_PATH}应更改为实际路径。总结使用PPython,可以丢弃诸如exec()之类的shell调用,从而允许开发返回到逻辑本身。

最新推荐
猜你喜欢