参考原文:
https://blog.csdn.net/u011957758/article/details/72873567
如何调用php标准库的函数
实战场景:想写一个简单的获取token的函数。token由任意前缀+随机数组成。
重点:随机数部分联想到了php有实现了,可直接调用。
1、引入php标准库头文件
搜索rand函数定义的文件:
grep -rn "PHP_FUNCTION(RAND)" ./ext
找到在/ext/standard/rand.c里头。我们要找的是头文件,故进一份分析,rand函数主要核心方法是调用了php_rand函数,发现原来是需要引入:
#include "php_rand.h"
是不是这个头文件里头声明的函数都可以调用呢?
答案是no,只能调用php_rand.h 头文件声明的PHPAPI的函数。
2、使用标准库的函数
如果不知道怎么使用可以这么分析:在PHP_FUNCTION(rand)函数中,找到调用的例子:
PHP_FUNCTION(rand)
{
long min;
long max;
long number;
int argc = ZEND_NUM_ARGS();
if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE)
return;
number = php_rand(TSRMLS_C);//TSRMLS_C代表线程安全,此处可直接使用,用的时候照着那个传就行。如果参数是别的,需要找参数的来源,在源文件中搜索或者参数是php调用的时候传的,找到参数的意义,就好了。
if (argc == 2) {
RAND_RANGE(number, min, max, PHP_RAND_MAX);
}
RETURN_LONG(number);
}
可以发现关键的实现代码是:
number = php_rand(TSRMLS_C);
RAND_RANGE(number, min, max, PHP_RAND_MAX);
好了,调用技能get到了
3、函数的实现
需要先添加PHP_FE(get_token, NULL) 注册函数,后实现函数。
PHP_FUNCTION(get_token) {
// 1.定义参数
long min = 1;
long max = 100;
char *prefix;
int prefix_len;
long number;
char sz[10];
// 2.接收token的前缀
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prefix, &prefix_len) == FAILURE) {
return;
}
// 3.获取随机数
number = php_rand(TSRMLS_C);
RAND_RANGE(number, min, max, PHP_RAND_MAX);
// 4.随机数转成字符串,方便拼接,否则会报make时候会有错误提示。
sprintf(sz, "%d", number);
// 5.拼接前缀与随机数
strcat(prefix, sz);
// 6.返回结果
RETURN_STRING(prefix, 1);
}
重新走一波编译安装流程(phpize && make && make install && /etc/init.d/php-fpm restart)
测试:
<?php
$token = get_token('test');
echo $token;
至此,调用php标准库done。
如何调用php原生的函数
实战场景:还是想写一个简单的获取token的函数。token由任意前缀+随机数组成。
重点:随机数部分用php原生的函数mt_rand实现。那么c扩展怎么调用原生的php函数呢?
1、详解重点方法call_user_function
官方的定义:
ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);
ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC);
竟然有两个函数,通过查看源码./Zend/zend_execute_API.c
是的,call_user_function封装了call_user_function_ex,直接使用call_user_function就好了。
参数讲解:
![](https://img.haomeiwen.com/i5350978/7c552f6e2e451cdc.png)
2、函数的实现
需要先添加PHP_FE(get_token_b, NULL) 注册函数.
//定义一个将整形转成zval型的函数(在查询鸟哥怎么用call_user_function的时候,发现的函数,原先是字符串变zval型,给稍微改了下整形变zval型)
static zval *_change_long_zval(long num)
{
zval *ret;
MAKE_STD_ZVAL(ret);
if (num) {
ZVAL_LONG(ret, num);
} else {
ZVAL_NULL(ret);
}
return ret;
}
PHP_FUNCTION(get_token_b) {
long min; // 随机数最小值
long max; // 随机数最大值
char *prefix; // 前缀
int prefix_len; // 前缀长度
char sz[10]; // 长整型转字符串时候用到
zval *func_name; // 函数名字
zval *retval; // 返回值
zval *params[1]; // 装参数的数组
// 获取参数
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll", &prefix, &prefix_len, &min, &max) == FAILURE) {
return;
}
// 申请一个内存
MAKE_STD_ZVAL(func_name);
// 赋值要调用的函数
ZVAL_STRING(func_name,"mt_rand", 1);
// 设置参数
params[0] = _change_long_zval(min);
params[1] = _change_long_zval(max);
// 申请返回值的内存空间
MAKE_STD_ZVAL(retval);
// 调用函数
if(call_user_function(CG(function_table),NULL,func_name,retval,2,params TSRMLS_DC)==FAILURE){
return;
}
// 转字符串
sprintf(sz, "%d", Z_LVAL_P(retval));
// 拼接返回结果
strcat(prefix, sz);
RETURN_STRING(prefix, 1);
}
测试:
<?php
$token = get_token_b('test',1,1000);
echo $token;
调用php原生函数done。
如何调用php写的函数
实战场景:还是想写一个简单的获取token的函数。token由任意前缀+随机数组成。
重点:随机数部分用我们自己写的php函数来实现。那么c扩展怎么调用自己写的php函数呢?
1、重点函数
当然还是call_user_function
2、函数的实现
需要先添加PHP_FE(get_token_c, NULL) 注册函数.
PHP_FUNCTION(get_token_c) {
zval *func_name;
zval *args;
zval *retval;
zval *params[1];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &func_name, &args) == FAILURE) {
return;
}
if (Z_TYPE_P(func_name) != IS_STRING){
return;
}
params[0] = args;
MAKE_STD_ZVAL(retval);
if(call_user_function(CG(function_table),NULL,func_name,retval,1,params TSRMLS_DC)==FAILURE){
return;
}
RETURN_STRING(Z_STRVAL_P(retval),1);
}
测试:
function get_token_demo($prefix){
return "token :".$prefix.mt_rand(1,1000);
}
echo get_token_c("get_token_demo","test");
至此,三种调用都已经
以上
欢迎大家关注我的公众号
网友评论