PHP:最初のPHP拡張を作成する
4014 ワード
今日はPHP拡張の入門文章をいくつか見ましたが、とても良い文章ですが、読むのはやはり大変です.主に、ライフサイクル、メモリ割り当て、SAPIという概念が分からないからです.そしてコードの中はマクロだらけで、ソースコードを調べなければ、天書を読むのと変わらない.だからソースコードの角度からhelloを分析することを記録したいです.cこのファイルの過程、他の文章の中にある私は繰り返しません.私は先にコードを置いて、ここには元の文章とは異なる部分があります.
次の3つのファイルが含まれているフォルダを勝手に作成します.
config.m4
php_hello.h
hello.c
次のコマンドを実行して、拡張を検証します.
原文と違いここではzend_を使いますfunction_function_ではなくentryentry.これはPHPのバージョンと関係があります.そうしないとコンパイルが間違ってしまいます.
まずこのコードを見てみましょう
PHP公式文書を見ると、そう書く可能性もあります.
結局、あなたが理解できないマクロの定義を見つければいいのですが、zend_を探してみましょう.function_entry、私のソースコードは下のパスの下にあるので、私は先にcdを行きます.
次のコマンドでzend_を探しますfunction_entryの定義.
発見はzend_API.hこの書類.
ソースコードは、関数の情報を格納する構造体です.
続いてPHP_を見ますFE,同様に次のコマンドを用いる.
次の結果が得られます.
ZEND_を探してFE、次は書かないで、最後にこの定義だと調べました.
実は関数構造体に関する情報であり、以前のzend_function_entry対応.
zend_を見てmodule_entryというコードは、実は作り方も上を参照して、#if ZEND_MODULE_API_NO>=20010901はapiバージョンが20010901(これは年月日)以上であるか否かを判断するためのものであり、それより大きい場合はSTANDARD_をコンパイル期間に含めるMODULE_HEADERというマクロ、これらの情報は以下のソースファイルで見つけることができます.ZEND_MODULE_API_NOこのマクロもこのファイルに定義されています.
最後にこれを言います
実は私もよくわかりませんがZEND_を調べましたGET_MODULEというマクロは、実行時にZendエンジンにモジュールの名前を取得するための関数です.今日はたぶんここまでで、次回は関数の帯数の場合を書きます.
次の3つのファイルが含まれているフォルダを勝手に作成します.
config.m4
PHP_ARG_ENABLE(hello, whether to enable Hello
World support,
[ --enable-hello Enable Hello World support])
if test "$PHP_HELLO" = "yes"; then
AC_DEFINE(HAVE_HELLO, 1, [Whether you have Hello World])
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi
php_hello.h
#ifndef PHP_HELLO_H
#define PHP_HELLO_H 1
#define PHP_HELLO_WORLD_VERSION "1.0"
#define PHP_HELLO_WORLD_EXTNAME "hello"
PHP_FUNCTION(hello_world);
extern zend_module_entry hello_module_entry;
#define phpext_hello_ptr &hello_module_entry
#endif
hello.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_hello.h"
//
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
{NULL, NULL, NULL}
};
//
// , , ,
zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_HELLO_WORLD_EXTNAME,
hello_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_HELLO_WORLD_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
// Dynamic Loading,
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif
//
PHP_FUNCTION(hello_world)
{
RETURN_STRING("Hello World", 1);
}
次のコマンドを実行して、拡張を検証します.
phpize
./configure
make
php -dextension=modules/hello.so -r "echo hello_world();"
原文と違いここではzend_を使いますfunction_function_ではなくentryentry.これはPHPのバージョンと関係があります.そうしないとコンパイルが間違ってしまいます.
まずこのコードを見てみましょう
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
{NULL, NULL, NULL}
};
PHP公式文書を見ると、そう書く可能性もあります.
static zend_function_entry hello_functions[] = {
PHP_FE(hello_world, NULL)
ZEND_FE_END
};
結局、あなたが理解できないマクロの定義を見つければいいのですが、zend_を探してみましょう.function_entry、私のソースコードは下のパスの下にあるので、私は先にcdを行きます.
/usr/local/Cellar/php56/5.6.32_8/include/php
次のコマンドでzend_を探しますfunction_entryの定義.
grep -rnw . -e 'zend_function_entry'
発見はzend_API.hこの書類.
./Zend/zend_API.h:41:} zend_function_entry;
ソースコードは、関数の情報を格納する構造体です.
typedef struct _zend_function_entry {
const char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
const struct _zend_arg_info *arg_info;
zend_uint num_args;
zend_uint flags;
} zend_function_entry;
続いてPHP_を見ますFE,同様に次のコマンドを用いる.
grep -rnw . -e 'PHP_FE'
次の結果が得られます.
./main/php.h:352:#define PHP_FE ZEND_FE
ZEND_を探してFE、次は書かないで、最後にこの定義だと調べました.
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeo
f(struct _zend_arg_info)-1), flags },
#define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
実は関数構造体に関する情報であり、以前のzend_function_entry対応.
zend_を見てmodule_entryというコードは、実は作り方も上を参照して、#if ZEND_MODULE_API_NO>=20010901はapiバージョンが20010901(これは年月日)以上であるか否かを判断するためのものであり、それより大きい場合はSTANDARD_をコンパイル期間に含めるMODULE_HEADERというマクロ、これらの情報は以下のソースファイルで見つけることができます.ZEND_MODULE_API_NOこのマクロもこのファイルに定義されています.
zend_modules.h
最後にこれを言います
// Dynamic Loading,
#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif
実は私もよくわかりませんがZEND_を調べましたGET_MODULEというマクロは、実行時にZendエンジンにモジュールの名前を取得するための関数です.今日はたぶんここまでで、次回は関数の帯数の場合を書きます.