美文网首页
php扩展开发(二)类开发

php扩展开发(二)类开发

作者: mafa1993 | 来源:发表于2020-04-06 21:03 被阅读0次

php扩展开发(二)类开发

类开发

  1. 实现目标,后面我们将根据这个结构进行扩展的开发
$server = new myServer('0.0.0.0',6000);
$server->on('request',function(){
    
});

$server->start(); //调用c函数启动
//myServer类的大概结构
class MyServer{
    private $port,$ip;
    public function __construct($ip,$port){
        
    }
    
    public function on($name,$cb){
        
    }
    
    public function start(){
        
    }
}
  1. 这里使用server.c作为扩展文件,代码来源于网络
    • server.c 放入到src目录下 myext/src/server.path
//这个文件我们叫做server.c,放入到src目录下
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#define LISTENQ 10
#define MAX_BUF_SIZE 1024
int server(char *ip, int *port)
{  


    int listenfd;
    int connfd;
    int n;
    socklen_t len;
    struct sockaddr_in servaddr;
    struct sockaddr_in cliaddr;
    char buffer[MAX_BUF_SIZE];
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_aton(ip, &(servaddr.sin_addr));
    servaddr.sin_port = htons(port);
    bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    listen(listenfd, LISTENQ);
    for (;;) {
        len = sizeof(cliaddr);
        connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
        for (;;) {
            n = read(connfd, buffer, MAX_BUF_SIZE);
            if (n <= 0) {
                close(connfd);
                break;
            }
            write(connfd, buffer, n);  
        }
    }
    close(listenfd);
}
  1. 修改config.m4
dnl If your extension references something external, use with:
dnl PHP_ARG_xxx都是zend引擎带的,如果依赖外部的lib库或者扩展,需要这块
dnl PHP_ARG_WITH(myext, for myext support,
dnl Make sure that the comment is aligned:
dnl [  --with-myext             Include myext support])

dnl Otherwise use enable:

PHP_ARG_ENABLE(myext, whether to enable myext support,
dnl Make sure that the comment is aligned:
[  --enable-myext          Enable myext support], no)

if test "$PHP_MYEXT" != "no"; then
  AC_DEFINE(HAVE_MYEXT, 1, [ Have myext support ])
dnl 引入文件
  PHP_SUBST(MYEXT_SHARED_LIBADD)
dnl 定义一个新的参数,参数1为函数名,参数2为依赖的文件(可以引入多个),其他不用修改
dnl 多文件引入,需要使用变量 这里为相对路径,使用空格分隔,下面引用变量时,需要使用$files
dnl myext.c相当于中间文件,server.c是真正的源码
  files=“myext.c src/server.c”
  PHP_NEW_EXTENSION(myext, $files, $ext_shared)
fi

PHP_SUBST(CURL_SHARED_LIBADD)

  1. 修改myext.c
    • 定义类
    • 修改主要包含以下主要内容
    • PHP_METHOD定义类方法
    • zend_function_entry server_method 方法绑定到类
    • PHP_MINIT_FUNCTION 模块初始化时调用的函数,在里面进行类绑定,参数接收
/* myext extension for PHP */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_myext.h"

/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
    ZEND_PARSE_PARAMETERS_START(0, 0) \
    ZEND_PARSE_PARAMETERS_END()
#endif

/* {{{ void myext_test1()
 */
PHP_FUNCTION(myext_test1)
{
    ZEND_PARSE_PARAMETERS_NONE();

    php_printf("The extension %s is loaded and working!\r\n", "myext");
}
/* }}} */

/* {{{ string myext_test2( [ string $var ] )
 */
PHP_FUNCTION(myext_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_FUNCTION(hello_world)
{
    zend_string *strg;
    
    strg = strpprintf(0,"Hello Wrold!");
    RETURN_STR(strg); //返回string
}


/**
  定义一个类实体,相当于定义了一个class,但是class名没有定义,可以理解为声明了一个空间
**/
zend_class_entry *my_server;

//定义方法
/**
 * @params MyServer为类的名字,这个名字和zend_class_entry定义的名字可以不一样
 * @params 方法
**/
PHP_METHOD(MyServer,__construct){
    //声明变量,用于接收传入的参数
    char *ip;
    long *port;

    //解析变量,变量验证,zend_num_args获取变量数
    if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,'sl') == FAILURE){ //等于FAILURE 表示类型验证失败
        //s string l long d double r resoce o object 
        RETURN_NULL();
    }
    //将参数和属性绑定,类实体,获取this,变量名,长度,绑定给那个变量
    //这里操作相当于$this->ip = $ip;
    zend_update_property_string(my_server,getThis(),"ip",sizeof("ip")-1,ip);
    zend_update_property_string(my_server,getThis(),"port",sizeof("port")-1,port);
    //zval也可以定义变量
}

PHP_METHOD(MyServer,on){
    
}

//调用start
PHP_METHOD(MyServer,start){
    //server()
    //zend定义变量,可以不用类型声明
    zval *ip;//从属性中获取ip,port strat
    zval *port;
    printf("start \n");
    zend_read_property(my_server,getThis(),"ip",sizeof("ip")-1,0,&ip); //读取属性值,赋值给变量ip,引用传值,会绑定变化
    zend_read_property(my_server,getThis(),"port",sizeof("port")-1,0,&port);
    server(ip,Z_LVAL(*port)); //调用server.c中的方法, Z_LVAL相当于类型转化
}

//定义类中包含的方法,用于注册到类
zend_function_entry server_method[] = {
    //类名,方法名,成员属性,访问属性
    ZEND_ME(MyServer,__construct,NULL,ZEND_ACC_PUBLIC)
    ZEND_ME(MyServer,on,NULL,ZEND_ACC_PUBLIC)
    ZEND_ME(MyServer,start,NULL,ZEND_ACC_PUBLIC)
    {NULL,NULL,NULL}
};


/* {{{ PHP_MINIT_FUNCTION 模块初始化,注册类
 */
PHP_MINIT_FUNCTION(MyServer)
{
    zend_class_entry ce;
    SLASH_STARTUP(http_util)
    //初始注册类,MyServer为注册类的名字,方法实体,前面已经定义
    INIT_CLASS_ENTRY(ce,"MyServer",server_method);
    my_server=zend_register_internal_class(&ce TSRMLS_CC); //注册到php内核,线程安全,保证变量不会污染
    //声明属性,绑定到的类,属性名,长度,访问属性
    zend_declare_property_null(my_server,"ip",sizeof("ip"-1),ZEND_ACC_PRIVATE);
    zend_declare_property_null(my_server,"port",sizeof("port"-1),ZEND_ACC_PRIVATE);
    return SUCCESS;
}



/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(myext)
{
#if defined(ZTS) && defined(COMPILE_DL_MYEXT)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif

    return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(myext)
{
    php_info_print_table_start();
    php_info_print_table_header(2, "myext support", "enabled");
    php_info_print_table_end();
}
/* }}} */



//请求初始化阶段
/*PHP_RINIT_FUNCTION(){

    return SUCCESS;
}
//函数销毁阶段
PHP_MSHUTDOWN_FUNCTION(){

}
//请求销毁阶段
PHP_RSHUTDOWN_FUNCTION(){

}


/* {{{ arginfo
 */
ZEND_BEGIN_ARG_INFO(arginfo_myext_test1, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_myext_test2, 0)
    ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ myext_functions[]
 */
static const zend_function_entry myext_functions[] = {
    PHP_FE(myext_test1,     arginfo_myext_test1)
    PHP_FE(myext_test2,     arginfo_myext_test2)
    PHP_FE(hello_world,NULL)
    PHP_FE_END
};
/* }}} */

/* {{{ myext_module_entry
 */
zend_module_entry myext_module_entry = {
    STANDARD_MODULE_HEADER,
    "myext",                    /* Extension name */
    myext_functions,            /* zend_function_entry */
    PHP_MINIT(myext),                           /* PHP_MINIT - Module initialization */
    NULL,                           /* PHP_MSHUTDOWN - Module shutdown */
    PHP_RINIT(myext),           /* PHP_RINIT - Request initialization */
    NULL,                           /* PHP_RSHUTDOWN - Request shutdown */
    PHP_MINFO(myext),           /* PHP_MINFO - Module info */
    PHP_MYEXT_VERSION,      /* Version */
    STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_MYEXT
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(myext)
#endif
  1. 编译出错,暂未调试通过
In file included from /usr/local/include/php/main/php.h:37:0,
                 from /home/php/php-7.3.9/ext/myext/myext.c:7:
/usr/local/include/php/Zend/zend_API.h:128:45: error: ‘zm_startup_myext’ undeclared here (not in a function)
 #define ZEND_MODULE_STARTUP_N(module)       zm_startup_##module

在zend_module_entry myext_module_entry里面调用PHP_MINIT时会触发PHP_MINIT_FUNCTION出了问题,c基础有限,暂未解决

相关文章

网友评论

      本文标题:php扩展开发(二)类开发

      本文链接:https://www.haomeiwen.com/subject/wnjiphtx.html