php扩展开发(二)类开发
类开发
- 实现目标,后面我们将根据这个结构进行扩展的开发
$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(){
}
}
- 这里使用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);
}
- 修改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)
- 修改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
- 编译出错,暂未调试通过
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基础有限,暂未解决
网友评论