php第三方函数库,菜鸟学php扩展 之 实战如何在扩展里调第三方函数(标准库/原生/本身写的)(六)...

前言

通过上文菜鸟学php扩展 之 详解php扩展的参数返回(五)的笔记,基本上建立一个扩展的基础技能get到了。

本文主要想作下如下三个问题的笔记:

1.如何调用php标准库的函数?

2.如何调用php原生的函数?

3.如何调用php写的函数?web

正文

如何调用php标准库的函数?

实战场景:想写一个简单的获取token的函数。token由任意前缀+随机数组成。数组

重点:随机数部分联想到了php有实现了,可直接调用。安全

引入php标准库头文件

搜索rand函数定义的文件:数据结构

grep -rn "PHP_FUNCTION(RAND)" ./ext

找到在/ext/standard/rand.c里头。咱们要找的是头文件,故进一份分析,rand函数主要核心方法是调用了php_rand函数,发现原来是须要引入:svg

#include"php_rand.h"

是否是这个头文件里头声明的函数均可以调用呢?函数

答案是no,只能调用php_rand.h 头文件声明的PHPAPI的函数。php-fpm

使用标准库的函数

若是不知道怎么使用能够这么分析:在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);

}

能够发现关键的实现代码是:ui

number = php_rand(TSRMLS_C);

RAND_RANGE(number, min, max, PHP_RAND_MAX);

好了,调用技能get到了

函数的实现

须要先添加PHP_FE(get_token, NULL) 注册函数(不懂请移步菜鸟学php扩展 之 hello world(一)),后实现函数。

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)

测试:

$token = get_token('test');

echo $token;

执行文件获得:test12

至此调用php标准库的技能get到了。

如何调用php原生的函数?

实战场景:仍是想写一个简单的获取token的函数。token由任意前缀+随机数组成。

重点:随机数部分用php原生的函数mt_rand实现。那么c扩展怎么调用原生的php函数呢?

详解重点方法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就行了。

参数讲解:

参数

讲解

HashTable

Zend使用HashTable来存储PHP函数,function_table用于指定从哪一个HashTable中获取函数。一般应该用CG(function_table),展开就是compiler_globals.function_table,compiler_globals是一个用来存储编译器数据的全局数据结构(与其对应的还有个EG宏,即executor_globals,它用来存储执行器数据)。compiler_globals.function_table里面存储了全部咱们能够在PHP页面里面调用的函数,包括Zend内建函数、PHP标准库函数、模块导出的函数以及用户使用PHP代码定义的函数。

object_pp

一个对象,当指定该值时,Zend会从对象的函数表中获取函数,老是设为NULL。

function_name

必须是string型的zval,存储咱们但愿调用的函数的名称。为何使用zval而不是直接用char*,是由于Zend考虑到大部分状况下,咱们都是从用户那得到参数,固然也能够手动建立一个string型的zval传给它。

retval_ptr

函数的返回值,Zend执行完指定的函数后,它就将返回值的指针填充到这里。申请空间MAKE_STD_ZVAL,过后这个容器空间的销毁释放工做得由zval_ptr_dtor(&ret_ptr)来作。

param_count

标识参数个数的整数

params

包含具体参数的数组

函数的实现

须要先添加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);

}

测试:

$token = get_token_b('test',1,1000);

echo $token;

执行文件获得:test212

至此调用php原生函数的技能get到了。

如何调用php写的函数?

实战场景:仍是想写一个简单的获取token的函数。token由任意前缀+随机数组成。

重点:随机数部分用咱们本身写的php函数来实现。那么c扩展怎么调用本身写的php函数呢?

重点函数

固然仍是call_user_function

函数的实现

须要先添加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");

执行文件获得:test782

至此调用本身写的php函数的技能get到了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值