php的扩展-PHP语言扩展的实现

本文主要向您介绍PHP语言扩展的实现,并通过具体的例子向您展示。 希望对您学习php语言有所帮助。

PHP的扩展实现后有两种形式,一种是扩展一个新的方法,一种是扩展一个类。

php版本是php7

1. 扩展方法

准备代码目录

mkdir zcjcdzcj

新建三个文件,通过这三个文件生成扩展名(也有工具可以手动生成,具体参见参考文章)

//php_extension,extension.c**规范要注意**

php的扩展_php扩展curl

配置.m4、php_zcj.h、zcj.c

一份是phpize打算编译扩展的配置文件,一份是包含的头文件,一份是源代码文件。

config.m4是phpize的参数文件,--enable可以改为--witth,--enable是动态编译,--with是静态编译,不知道两者有什么区别,c/c++高手还是需要它让大家知道。

PHP_ARG_ENABLE(zcj, whether to enable zcj support,Make sure that the comment is aligned:
[  --enable-zcj           Enable zcj support])if test "$PHP_ZCJ" != "no"; then
    PHP_NEW_EXTENSION(zcj, zcj.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi

我这里的扩展名是zcj,如果你的扩展名不一样,可以改成你自己的扩展名,注意大小写。 下面的php_zcj.h也是一样,将zcj替换成你的扩展名,注意一个规范,添加到源代码中的函数应该在头文件中声明。

php_zcj.h

#ifndef PHP_ZCJ_H #define PHP_ZCJ_H

externzend_module_entry zcj_module_entry;#define phpext_zcj_ptr &zcj_module_entry#define PHP_ZCJ_VERSION "0.1.0"#define PHP_ZCJ_EXTNAME "zcj"//函数的原型声明,以便建立过程能够正确进行

PHP_FUNCTION(zcj);

PHP_FUNCTION(zcj_long);

PHP_FUNCTION(zcj_double); #万一

接下来就可以编写代码来实现扩展功能了。

具体怎么写,暴露php使用的技巧,在zend_function_entry结构体中添加几行PHP_FE(),第一个参数函数名第二个为Null,函数返回string类型,返回其他类型为a有点不同,所以请注意,我不知道为什么,只知道如何。

还有一些预处理php的扩展,这些无所谓。 不同版本该工具生成的预处理是不同的。

zcj.c

#ifdef HAVE_CONFIG_H#include "config.h"#endif
#include "php.h"#include "php_zcj.h"
double test(){
    return 3.13789;
}
PHP_FUNCTION(zcj)
{
    zend_string *strg;
    strg = strpprintf(0, "hello zcj. (from zcj module)");
    RETURN_STR(strg);
}
PHP_FUNCTION(zcj_long)
{
    RETURN_LONG(2001);
}
PHP_FUNCTION(zcj_double){
    RETURN_DOUBLE(test());
}const zend_function_entry zcj_functions[] = {
    PHP_FE(zcj, NULL)
    PHP_FE(zcj_long, NULL)
    PHP_FE(zcj_double, NULL)
    PHP_FE_END
};
zend_module_entry zcj_module_entry = {
    STANDARD_MODULE_HEADER,
    PHP_ZCJ_EXTNAME,
    zcj_functions,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    PHP_ZCJ_VERSION,
    STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_ZCJ#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()#endif
ZEND_GET_MODULE(zcj)#endif

然后

1.phpize初始化

2.生成makefile

3.生成so文件,放到php扩展目录下

phpize

./configure --with-php-config=/usr/local/php/bin/php-config

制作 && 制作安装

然后使用

php扩展curl_php的扩展

服务 php-fpm 重新启动

php -r “回显 zcj_long();”

输出成功,函数扩展写入

二、扩展类编译

编写zcjOop的扩展类

mkdir zcjOop cdzcjOop

还是三个文件

配置.m4

PHP_ARG_WITH(zcjOop, for zcjOop support, Make sure that the comment is aligned:
 [  --with-zcjOop             Include zcjOop support])if test "$PHP_ZCJOOP" != "no"; then
  PHP_NEW_EXTENSION(zcjOop, zcjOop.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi
php_zcjOop.h
#ifndef PHP_ZCJOOP_H#define PHP_ZCJOOP_Hextern zend_module_entry zcjOop_module_entry;#define phpext_zcjOop_ptr &zcjOop_module_entry#define PHP_ZCJOOP_VERSION "0.1.0"#define PHP_ZCJOOP_EXTNAME "zcjOop"#endif
zcjOop.c
#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "php.h"#include "php_zcjOop.h"
zend_class_entry *zcjOop_ce;//第一个参数是类名,第二个参数是类的方法
PHP_METHOD(zcjOop, learn);
PHP_METHOD(zcjOop, znb);

//如果方法需要接受参数,则执行接下来的三句 //ZEND_BEGIN_ARG_INFO_EX的最后一个参数1是传递的参数个数。

ZEND_BEGIN_ARG_INFO_EX(arginfo_zcjOop_learn, 0, 0, 1)//ZEND_ARG_INFO的第一个参数0表示是否通过引用传递。一般默认为0

ZEND_ARG_INFO(0, love)
ZEND_END_ARG_INFO()
 
PHP_FUNCTION(zcj_oop)
{
    zval *value=NULL;
    zend_string *type;
     if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &type, &value) == FAILURE) {
        return;
    }    
    //strg = strpprintf(0, "hello zcj_oop. (from zcj module)");
    RETURN_ZVAL(value,0,1);

}constzend_function_entry zcjOop_methods[] = {// 1 类名, // 2 方法名, // 3 zend_arg_info 的参数列表, // 4.访问权限 // ZEND_ACC_PUBLIC ZEND_ACC_PRIVATE ZEND_ACC_PROTECTED 是我们类上面的三个访问权限 // ZEND_ACC_CTOR 标记构造函数 // ZEND_ACC_DTOR 标识析构函数

    PHP_ME(zcjOop, learn, arginfo_zcjOop_learn, ZEND_ACC_PUBLIC)
    PHP_ME(zcjOop, znb, arginfo_zcjOop_learn, ZEND_ACC_PUBLIC)
};const zend_function_entry zcj_functions[] = {
    PHP_FE(zcj_oop, NULL)
    PHP_FE_END
};
PHP_METHOD(zcjOop, learn)
{
    char *love = NULL;
    //size_t love_len;
 
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &love) == FAILURE) {
        return;
    }
 
    // zend_update_property_string(zcjOop_ce,getThis(),"memory",sizeof("memory") - 1, love);
}
PHP_METHOD(zcjOop, znb)
{
    char *love = NULL;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &love) == FAILURE) {
        return;
    }
}
PHP_MINIT_FUNCTION(zcjOop)
{
    /* If you have INI entries, uncomment these lines
 *  REGISTER_INI_ENTRIES();
 *      */
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "zcjOop", zcjOop_methods);
 
    zcjOop_ce = zend_register_internal_class(&ce);
 
    zend_declare_property_null(zcjOop_ce, "memory",sizeof("memory") - 1, ZEND_ACC_PUBLIC);
    //返回成功进入下一个事件
    return SUCCESS;

}//zend_moduel_entry//扩展模块信息结构体的10个值的每个函数//第一个应该是起始指针,不知道是做什么用的//第三个是函数扩展,如果扩展需要一个函数php的扩展,只需填写一个zend_function_entry结构体变量名//第二个是扩展名。 您可以使用扩展字符列表或 PHP_extension_EXTNAME// PHP_MINIT(myfun); /*当PHP加载时,模块启动的函数被引擎调用。 这会提示引擎做一些初始化如资源类型、注册INI变量等。 */ 1// PHP_MSHUTDOWN(myfun); /* 当PHP完全关闭时,引擎会调用模块关闭函数。 通常用于取消注册 INI 条目 */// PHP_RINIT(myfun); /* 在每个 PHP 请求开始时,调用预请求启动函数。 通常用于管理预请求逻辑。 */// PHP_RSHUTDOWN(myfun); /* 每次PHP请求结束后,调用预请求关闭函数。 在清除请求之前始终应用逻辑来启动函数。 */// PHP_MINFO(myfun); /*调用phpinfo()时会调用模块信息函数,从而将模块信息复制出来。 */// 最后两个应该是一些扩展信息什么的

zend_module_entry zcjOop_module_entry = {
    STANDARD_MODULE_HEADER,
    "zcjOop",
    zcj_functions,
    PHP_MINIT(zcjOop),
    NULL,
    NULL,
    NULL,
    NULL,
    PHP_ZCJOOP_VERSION,
    STANDARD_MODULE_PROPERTIES
};/* }}} */
#ifdef COMPILE_DL_ZCJOOP#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE();#endif
ZEND_GET_MODULE(zcjOop)#endif