第一步 生成扩展demo Runing起来
生成扩展demo
我们以php-7.4.1版本为例。
进入 cd php-7.4.1/ext 此目录,有一个名为 ext_skel.php。我们用此脚本生在扩展demo步骤如下
./ext_skel.php --ext gwalker
这样就在 ext目录下生成 gwalker扩展目录,目录内容如下:
[root@gw gwalker]# ls
config.m4 config.w32 gwalker.c php_gwalker.h tests
接下来进行编译,安装到php扩展中
[root@gw gwalker]# phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
./configure --with-php-config=/data/php/bin/php-config
make && make install
修改php.ini 把生成的so加关联到扩展中去
extension=/data/php/lib/php/extensions/debug-non-zts-20190902/gwalker.so
这样就把gwalker扩展加到php环境中去了。可以通过cli命令验证查看
./php -m | grep gwalker
gwalker
也可以重新启动php-fpm(或php内置web服务),通过浏览器验证
<?php
phpinfo();
运行demo扩展
打开gwalker.c源码文件阅读代码发现生成的demo给咱们实现好了,gwalker_test1()与gwalker_test2()函数。
...
/* {{{ void gwalker_test1()
*/
PHP_FUNCTION(gwalker_test1)
{
ZEND_PARSE_PARAMETERS_NONE();
php_printf("The extension %s is loaded and working!\r\n", "gwalker");
}
/* }}} */
/* {{{ string gwalker_test2( [ string $var ] )
*/
PHP_FUNCTION(gwalker_test2)
{
char *var = "World";
size_t var_len = sizeof("World") - 1;
zend_string *retval;
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();
retval = strpprintf(0, "Hello %s", var);
RETURN_STR(retval);
}
/* }}}*/
...
那咱们测试下这两个函数,是否能够正常运行
<?php
gwalker_test1();
echo "\n";
echo gwalker_test2('gongwen');
The extension gwalker is loaded and working!
Hello gongwen
第二步 编码一元二次方程求解函数扩展
函数功能如下:
求解 ax^2 + bx +c = 0;
如果a为0则降级为一元一次方程求解。否则有无解的话返回布尔false,一个解返回数组[x],两个解返回数组[x1,x2]
编码求解函数 getSolutionOVQE
注 OVQE 为Quadratic equation of one variable
PHP_FUNCTION(getSolutionOVQE)
{
double a = 0;
double b = 0;
double c = 0;
// 定义x1,x2用来保放一元二次方程的两个解
double x1 = 0;
double x2 = 0;
// detal 记录 b^2 - 4ac的值
double detal = 0;
// =========参数接收处理阶段 begin ===============
ZEND_PARSE_PARAMETERS_START(2, 3) //接收参数,最少两个参数,最多3个参数
Z_PARAM_DOUBLE(a) // 接收第一参数,赋a
Z_PARAM_DOUBLE(b) // 接收第二参数,赋b
Z_PARAM_OPTIONAL // 表示后面的参数为选填项
Z_PARAM_DOUBLE(c) // 接收第二参数,赋c
ZEND_PARSE_PARAMETERS_END();
// =========参数接收处理阶段 end ===============
// 如果a与b两个系统数都为0,则返回false
if (a == 0 && b == 0)
{
RETURN_FALSE;
}
// 扩展开发通过return_value这个变量设置方法的返回值
array_init(return_value);
// 如果a=0 ,则降级为一元一次方程求解
if (a == 0)
{
x1 = -1 * (c/b);
add_index_double(return_value, 0, x1);
return;
}
detal = pow(b, 2) - 4 * a * c;
if (detal == 0)
{
x1 = (-b + sqrt(detal)) / (2 * a);
add_index_double(return_value, 0, x1);
return;
}
else if (detal > 0)
{
x1 = (-b + sqrt(detal)) / (2 * a);
x2 = (-b - sqrt(detal)) / (2 * a);
add_index_double(return_value, 0, x1);
add_index_double(return_value, 1, x2);
return;
}
// 都不符合是返回false
RETURN_FALSE;
}
注册 getSolutionOVQE 函数
static const zend_function_entry gwalker_functions[] = {
PHP_FE(gwalker_test1, arginfo_gwalker_test1)
PHP_FE(gwalker_test2, arginfo_gwalker_test2)
PHP_FE(getSolutionOVQE, NULL)
PHP_FE_END
};
重新编译,测试
make && make install
<?php
$v = getSolutionOVQE(0,1,2);
echo '<pre>';
var_dump($v);
$h = getSolutionOVQE(1,2,1);
var_dump($h);
$h = getSolutionOVQE(1,-7,12);
var_dump($h);
$h = getSolutionOVQE(5,7,1);
var_dump($h);
$h = getSolutionOVQE(0,0,0);
var_dump($h);
$h = getSolutionOVQE(2,1,20);
var_dump($h);
$h = getSolutionOVQE(90,100,25);
var_dump($h);
$h = getSolutionOVQE(0,100,25);
var_dump($h);
exit;
输出如下:
array(1) {
[0]=>
float(-2)
}
array(1) {
[0]=>
float(-1)
}
array(2) {
[0]=>
float(4)
[1]=>
float(3)
}
array(2) {
[0]=>
float(-0.16148351928655)
[1]=>
float(-1.2385164807135)
}
bool(false)
bool(false)
array(2) {
[0]=>
float(-0.37987346332398)
[1]=>
float(-0.73123764778713)
}
array(1) {
[0]=>
float(-0.25)
}
附php代码版求一元二次方程
function php_getSolutionOVQE($a,$b,$c=0){
$x1=0;
$x2=0;
$detal=0;
if($a==0 && $b==0){
return false;
}
if($a==0){
$x1 = -1 * ($c/$b);
return [$x1];
}
$detal = pow($b,2) - 4*$a*$c;
if($detal == 0){
$x1 = (-1*$b + sqrt($detal)) / (2 * $a);
return [$x1];
}else if($detal > 0){
$x1 = (-1*$b + sqrt($detal)) / (2 * $a);
$x2 = (-1*$b - sqrt($detal)) / (2 * $a);
return [$x1,$x2];
}
return false;
}
性能比较
现在分别进行100万次的一元二次方程求解。看下所用耗时
c扩展版如下(执行5次,用时记录如下):
use time : 0.993971824646 s
use time : 0.99442791938782 s
use time : 0.99134087562561 s
use time : 0.99235987663269 s
use time : 0.99243712425232 s
php代码版如下(执行5次,用时记录如下):
use time : 2.2686109542847 s
use time : 2.2673828601837 s
use time : 2.2710490226746 s
use time : 2.3082909584045 s
use time : 2.2692041397095 s
观察结果性能提升了2.2倍
注 性能测试代码如下:
c扩展版
<?php
$start_time = microtime(true);
echo '<pre>';
for($i = 1;$i<=1000000;$i++){
$a = $i+2;
$b = $i*3;
$c = $i+6;
$re = getSolutionOVQE($a,$b,$c);
//var_dump($re);
}
$end_time = microtime(true);
echo 'use time : '.($end_time-$start_time).' s';
exit;
php代码版
<?php
function php_getSolutionOVQE($a,$b,$c=0){
$x1=0;
$x2=0;
$detal=0;
if($a==0 && $b==0){
return false;
}
if($a==0){
$x1 = -1 * ($c/$b);
return [$x1];
}
$detal = pow($b,2) - 4*$a*$c;
if($detal == 0){
$x1 = (-1*$b + sqrt($detal)) / (2 * $a);
return [$x1];
}else if($detal > 0){
$x1 = (-1*$b + sqrt($detal)) / (2 * $a);
$x2 = (-1*$b - sqrt($detal)) / (2 * $a);
return [$x1,$x2];
}
return false;
}
$start_time = microtime(true);
echo '<pre>';
for($i = 1;$i<=1000000;$i++){
$a = $i+2;
$b = $i*3;
$c = $i+6;
$re = php_getSolutionOVQE($a,$b,$c);
//var_dump($re);
}
$end_time = microtime(true);
echo 'use time : '.($end_time-$start_time).' s';
exit;