PHP扩展开发-内核执行流程与扩展结构

在开发扩展以前最好了解下PHP内核的执行流程PHP大概包括三个方面

 

SAPIphp

Zend VMlinux

内部扩展apache

  • Zend VM是PHP的虚拟机与JVM相似都是各自语言的编译/执行的核心。它们都会把各自的代码先编译为一种中间代码PHP的一般叫 opcodeJava一般叫bytecode不一样的是PHP的opcode直接被Zend VM的执行单元调用对应的C函数执行不会显示保留下来能够cache保留而Java一般是生成class文件保留下来。而这一点可能也是PHP interpreter的名称的由来吧。其实相对严格的C/C++等编译型语言PHP和Java更多的是结合了编译型和解释性的风格。api

  • SAPI能够看做是Zend VM向外界提供编译/执行PHP代码服务的方式和规范。不管是做为cli/cgi/fastcgi/apache_mod与其余程序交互仍是嵌入其余语 言中如C/C++等均可以经过SAPI的规范实现。它的一个重要数据结构就是sapi_module_struct(main/SAPI.h line 217)安全

  • 内部扩展部分能够看做是搭建在Zend VM和SAPI之上的库为PHP开发人员***能和易用性上的保证。Java的各类包/Python的各类模块功能相似不一样的是PHP中为了性能是用 C扩展来实现的相似的在Java中能够经过JNI来实现Python中如_socket和_select多路复用都不是原生Python实现。数据结构

生命周期

关于各类SAPI或者PHP自己的生命周期可能会和其余组件如apache耦合后续再细谈。关于PHP扩展的生命周期这里借用一张图。流程应该是很容易明白的关于这个过程网上也有不少资料再也不赘述。咱们开发扩展须要注意的几个地方也能够对应到图中的某些节点多线程

 

全局变量的定义一般是zend_modulename_globals框架

模块的初始化包括资源/类/常量/ini配置等模块级的初始化socket

请求的初始化包括与单次请求相关的一些初始化ide

请求的结束清理单次请求相关的数据/内存

模块的卸载清理模块相关的数据/内存

基本上咱们要作的就是按照上面的流程实现相关的内置函数定义本身的资源/全局变量/类/函数等。值得注意的地方是在在嵌入其余语言如Python或者被嵌入其余组件如apache时要当心多进程多线程相关的问题。

<img src="http://www.ahlinux.com/uploadfile/2015/0314/20150314114134554.jpg" title="b□" http:="" www.ahlinux.com="" php="" "="" target="_blank" class="keylink" data-bd-imgshare-binded="1" style="margin: 0px; padding: 3px; border: 1px solid rgb(204, 204, 204); max-width: 660px;">php-src/ext/ext_skel能够生成PHP扩展的框架


./ext_skel --extname=myext
[tan@tan ~/software/needbak/php-5.5.20/ext 12:24]$==> ls myext/
config.m4  config.w32  CREDITS  EXPERIMENTAL  myext.c  myext.php  php_myext.h  tests

比较重要的文件是config.m4固然还有源码config.m4文件可使用phpize命令生成configure文件其中说明了咱们是否开启模块以及外部依赖的库。

//config.m4
//若是你的扩展依赖其余外部库
dnl PHP_ARG_WITH(myext, for myext support,
dnl Make sure that the comment is aligned:
dnl [  --with-myext             Include myext support])

//扩展不依赖外部库
dnl PHP_ARG_ENABLE(myext, whether to enable myext support,
dnl Make sure that the comment is aligned:
dnl [  --enable-myext           Enable myext support])

//寻找并包含头文件
if test "$PHP_MYEXT" != "no"; then
  dnl Write more examples of tests here...

  dnl # --with-myext -> check with-path
  dnl SEARCH_PATH="/usr/local /usr"     # you might want to change this
  dnl SEARCH_FOR="/include/myext.h"  # you most likely want to change this
  dnl if test -r $PHP_MYEXT/$SEARCH_FOR; then # path given as parameter
  dnl   MYEXT_DIR=$PHP_MYEXT
  dnl else # search default path list
  dnl   AC_MSG_CHECKING([for myext files in default path])
  dnl   for i in $SEARCH_PATH ; do
  dnl     if test -r $i/$SEARCH_FOR; then
  dnl       MYEXT_DIR=$i
  dnl       AC_MSG_RESULT(found in $i)
  dnl     fi
  dnl   done
  dnl fi
  dnl
  dnl if test -z "$MYEXT_DIR"; then
  dnl   AC_MSG_RESULT([not found])
  dnl   AC_MSG_ERROR([Please reinstall the myext distribution])
  dnl fi

  dnl # --with-myext -> add include path
  dnl PHP_ADD_INCLUDE($MYEXT_DIR/include)

  //加载的lib位置
  dnl # --with-myext -> check for lib and symbol presence
  dnl LIBNAME=myext # you may want to change this
  dnl LIBSYMBOL=myext # you most likely want to change this 

  dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  dnl [
  dnl   PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $MYEXT_DIR/$PHP_LIBDIR, MYEXT_SHARED_LIBADD)
  dnl   AC_DEFINE(HAVE_MYEXTLIB,1,[ ])
  dnl ],[
  dnl   AC_MSG_ERROR([wrong myext lib version or lib not found])
  dnl ],[
  dnl   -L$MYEXT_DIR/$PHP_LIBDIR -lm
  dnl ])
  dnl
  dnl PHP_SUBST(MYEXT_SHARED_LIBADD)

  PHP_NEW_EXTENSION(myext, myext.c, $ext_shared)
fi
//php_myext.h
#ifndef PHP_MYEXT_H
#define PHP_MYEXT_H
extern zend_module_entry myext_module_entry;
#define phpext_myext_ptr &myext_module_entry
//导出符号在连接的时候有用
#ifdef PHP_WIN32
#   define PHP_MYEXT_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
#   define PHP_MYEXT_API __attribute__ ((visibility("default")))
#else
#   define PHP_MYEXT_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
//几个核心函数的声明
PHP_MINIT_FUNCTION(myext);
PHP_MSHUTDOWN_FUNCTION(myext);
PHP_RINIT_FUNCTION(myext);
PHP_RSHUTDOWN_FUNCTION(myext);
PHP_MINFO_FUNCTION(myext);
//自动生成的测试函数声明咱们本身定义的模块函数须要在此声明
PHP_FUNCTION(confirm_myext_compiled);   
//全局变量在这定义展开后是zend_myext_globals结构体
ZEND_BEGIN_MODULE_GLOBALS(myext)
  long  global_value;
  char *global_string;
ZEND_END_MODULE_GLOBALS(myext)
//线程安全与非线程安全下获取全局变量的方式
#ifdef ZTS
#define MYEXT_G(v) TSRMG(myext_globals_id, zend_myext_globals *, v)
#else
#define MYEXT_G(v) (myext_globals.v)
#endif
#endif  /* PHP_MYEXT_H */
//myext.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_myext.h"
//全局变量声明
ZEND_DECLARE_MODULE_GLOBALS(myext)
/* True global resources - no need for thread safety here */
static int le_myext;
//模块函数的导出
const zend_function_entry myext_functions[] = {
  PHP_FE(confirm_myext_compiled,  NULL)	   /* For testing, remove later. */
    PHP_FE_END  /* Must be the last line in myext_functions[] */
};
//模块结构
zend_module_entry myext_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
  STANDARD_MODULE_HEADER,
#endif
  "myext",
  myext_functions,
  PHP_MINIT(myext),
  PHP_MSHUTDOWN(myext),
  PHP_RINIT(myext),	   /* Replace with NULL if there's nothing to do at request start */
  PHP_RSHUTDOWN(myext),   /* Replace with NULL if there's nothing to do at request end */
  PHP_MINFO(myext),
#if ZEND_MODULE_API_NO >= 20010901
  PHP_MYEXT_VERSION,
#endif
  STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_MYEXT
ZEND_GET_MODULE(myext)
#endif
//ini配置文件的设置
PHP_INI_BEGIN()
  STD_PHP_INI_ENTRY("myext.global_value",	  "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_myext_globals, myext_globals)
  STD_PHP_INI_ENTRY("myext.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_myext_globals, myext_globals)
PHP_INI_END()
//初始化全局变量
static void php_myext_init_globals(zend_myext_globals *myext_globals)
{
  myext_globals->global_value = 0;
  myext_globals->global_string = NULL;
}
//模块加载时的函数
PHP_MINIT_FUNCTION(myext)
{
  /* If you have INI entries, uncomment these lines 
  REGISTER_INI_ENTRIES();
  */
  return SUCCESS;
}
//模块卸载时函数
PHP_MSHUTDOWN_FUNCTION(myext)
{
  /* uncomment this line if you have INI entries
  UNREGISTER_INI_ENTRIES();
  */
  return SUCCESS;
}
//请求初始化函数
PHP_RINIT_FUNCTION(myext)
{
  return SUCCESS;
}
//请求关闭函数
PHP_RSHUTDOWN_FUNCTION(myext)
{
  return SUCCESS;
}
//模块信息phpinfo
PHP_MINFO_FUNCTION(myext)
{
  php_info_print_table_start();
  php_info_print_table_header(2, "myext support", "enabled");
  php_info_print_table_end();
  /* Remove comments if you have entries in php.ini
  DISPLAY_INI_ENTRIES();
  */
}
//测试函数
PHP_FUNCTION(confirm_myext_compiled)
{
  char *arg = NULL;
  int arg_len, len;
  char *strg;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
    return;
  }
  len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "myext", arg);
  RETURN_STRINGL(strg, len, 0);
}
相关文章
相关标签/搜索