PHP7.4正式版发布已经好久了,而主打的新特性是FFI,今天我也来体验一把😎
FFI提供了高级语言直接的互相调用,而对于PHP来说,FFI让我们可以方便的调用C语言写的各种库。
刚好,有个小需求需要调用c代码来获取命令行窗口的大小(行数和列数)。我们的c代码是:
// filename cli_size.c
/**
* 通过函数 ioctl() 获得终端界面的参数
* @see https://blog.csdn.net/weixin_42205987/article/details/82080615
*/
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
struct winsize get_size()
{
struct winsize size;
ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
return size;
}
unsigned short get_cli_rows()
{
struct winsize size;
ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
return size.ws_row;
}
unsigned short get_cli_cols()
{
struct winsize size;
ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
return size.ws_col;
}
我们先把上面的c代码编译成动态链接库libcli_size.so
:
gcc -O2 -fPIC -shared -g cli_size.c -o libcli_size.so
开始写我们的php代码:
首先我们使用FFI::cdef()
函数声明我们要调用的这个库中的函数以及使用到的数据类型。
比如我们在这里要调用的三个函数get_cli_rows
(获取行数)、 get_cli_cols
(获取列数)、 get_size
(获取所有信息),我们把他们的声明作为FFI::cdef()
函数的第一个参数。看到下面的代码大家应该很熟悉,就是c语言的函数声明。
这里get_size
方法返回是一个结构体struct winsize
,所以我们也要把这个结构体的声明也写上。
FFI::cdef()
函数的第二个参数就是我们自己的库文件名了。
<?php
//filename cli_size.php
$ffi = FFI::cdef(<<<CTYPE
struct winsize {
unsigned short ws_row; /* rows, in characters */
unsigned short ws_col; /* columns, in characters */
unsigned short ws_xpixel; /* horizontal size, pixels */
unsigned short ws_ypixel; /* vertical size, pixels */
};
unsigned short get_cli_rows();
unsigned short get_cli_cols();
struct winsize get_size();
CTYPE, 'libcli_size.so');
接下来就是调用了
//继续上面的代码
var_dump($ffi->get_cli_rows());
var_dump($ffi->get_cli_cols());
var_dump($ffi->get_size());
然后运行它:
php cli_size.php
输出:
int(36) // get_cli_rows()的结果
int(150) // get_cli_cols()的结果
object(FFI\CData:struct winsize)#2 (4) { // get_size()的结果,也就是winsize结构体,
["ws_row"]=>
int(36)
["ws_col"]=>
int(150)
["ws_xpixel"]=>
int(1200)
["ws_ypixel"]=>
int(684)
}
通过上面可以看出c语言返回的unsigned short
类型在这里变成了php的int
, 结构体struct winsize
变成了一个FFI\CData
对象。
那我们怎么从结构体对象中取某一个属性值呢?
就按普通对象操作就可以了:
//继续上面的代码
var_dump($ffi->get_size()->ws_row);
输出:
int(36)
对于其他的c语言类型,PHP官方文档上都有对应的php类型说明,大家可以去看看。
以上示例代码都在这里
好了,新的编程体验,好不错吧~😎😎😎
参考:
- https://www.php.net/manual/zh/ffi.cdef.php
- https://www.php.net/manual/zh/class.ffi-cdata.php
评论