【ISSUE】[PHP7]エクステンションで自作関数を作る

0

2024年12月23日 17:28

はじめに

Swiftとかだとextensionを使って、元から存在する型(String, arrayとか)に任意の関数を追加することができます。

img

しかし、PHPのエクステンションはC言語で書かれています。そのため実装は大変なのですが、普通のPHPスクリプトと異なり高速で動作します。このエクステンションはPHP7 と PHP5 で大幅に変わったらしいのですが、基本的には変わっていないように感じました。

準備

PHP本体のソースを取得

img

指定したバージョンをチェックアウト

img

ここでは、PHP7.1.2 をチェックアウトしていきます。

img

雛形の作成

img

ビルド/動作確認

雛形をビルド/実行できるかを確認してみます

img

config.m4 を編集します。10行目あたりの

img
という箇所のコメントを外します。ここファイルでのコメントはdnlで表されます。
なので、dnlを消してください。

img
img

-d extension=./modueles/myext.so で .so ファイルをロードして、 Congratulations! You have successfully 〜 という表示が出れば準備完了です。

自作関数の登録と実装

今回は簡単なadd関数を自作することにします。add_extensionという関数名にしておきます。使用例としては

img

関数の登録

今回はconst zend_function_entry add_extension_functions[]add_extension関数を追加して行きます。変数名は特に指定されていないのでわかりやすくしておきましょう。

img
PHP_FE(add_extension, NULL)の第2引数にarg_infoという構造体を渡すとタイプヒンティングやリフレクション等が利用できるようになります。この説明については付録で書きます。

関数本体の実装

関数本体を実装するときにはPHP_FUNCTION()というマクロを利用します。

img

ZEND_PARSE_PARAMETERS_START(MIN, MAX)

第1引数は最小引数、第2引数は最大引数の個数を表します。

Z_PARAM

受け取る引数の型を指定して、どの変数に代入するかを指定します。型指定子とよばれ以下のように定義されています。

specifierFast ZPP API macroargs
|Z_PARAM_OPTIONAL
aZ_PARAM_ARRAY(dest)dest - zval*
AZ_PARAM_ARRAY_OR_OBJECT(dest)dest - zval*
bZ_PARAM_BOOL(dest)dest - zend_bool
CZ_PARAM_CLASS(dest)dest - zend_class_entry*
dZ_PARAM_DOUBLE(dest)dest - double
fZ_PARAM_FUNC(fci, fcc)fci - zend_fcall_info, fcc - zend_fcall_info_cache
hZ_PARAM_ARRAY_HT(dest)dest - HashTable*
HZ_PARAM_ARRAY_OR_OBJECT_HT(dest)dest - HashTable*
lZ_PARAM_LONG(dest)dest - long
LZ_PARAM_STRICT_LONG(dest)dest - long
oZ_PARAM_OBJECT(dest)dest - zval*
OZ_PARAM_OBJECT_OF_CLASS(dest, ce)dest - zval*
pZ_PARAM_PATH(dest, dest_len)dest - char*, dest_len - int
PZ_PARAM_PATH_STR(dest)dest - zend_string*
rZ_PARAM_RESOURCE(dest)dest - zval*
sZ_PARAM_STRING(dest, dest_len)dest - char*, dest_len - int
SZ_PARAM_STR(dest)dest - zend_string*
zZ_PARAM_ZVAL(dest)dest - zval*
Z_PARAM_ZVAL_DEREF(dest)dest - zval*
+Z_PARAM_VARIADIC('+', dest, num)dest - zval*, num int
*Z_PARAM_VARIADIC('*', dest, num)dest - zval*, num int

https://wiki.php.net/rfc/fast_zpp

実際に呼び出してみる

img

img

とりあえず関数のエクステンションを作り上げることまではできるようになりました。

記事を書く気力とプログラムを組む気力があれば、エクステンションでクラス作成もしてみたいと思います。

付録

PHP_FE

arg_info構造体

PHP_FEマクロの第2引数はReflection APIに対して関数の引数情報を提供するために使用されます。つまりは指定しなくても(NULLでも)動きますが、実装したExtensionを後悔する場合には必ずと言っていいほど必要になるので、実装しておく方が無難です。以下にmb_convert_encoding関数を例に示します。

mb_convert_encoding

img
この定義がされているphp/ext/mbstring/mbstring.cには以下のように記載されています

img

ZEND_BEGIN_ARG_INFO_EX

以下の4つの引数を指定します。

引数番号解説
1定義名(PHP_FEマクロの第2引数として指定する文字列)
2未使用
3返却フラグ(1: 参照を返す, 0: 受け取るだけ)
4必須引数の個数

ZEND_ARG_INFO

関数の引数の数だけ記述する必要があります。それぞれ以下の2つの引数を指定します。

引数番号解説
11: 参照渡し, 0: 値渡し
2仮引数名

ZEND_END_ARG_INFO

引数定義の終了を示します。

先ほどのを見返すと

img
となっています。必須引数が2となっていますが、これはZEND_ARG_INFOの定義順で必須になっていくので注意してください。また、ZEND_ARG_INFOの第1引数が0なので全て値渡しになります。

このPHP_FEZEND_ARG_INFOで行なった引数定義はReflectionFunctionクラスを用いて参照することができます

img
img
[cv:issue_marketplace_engineer]

0

診断を受けるとあなたの現在の業務委託単価を算出します。今後副業やフリーランスで単価を交渉する際の参考になります。また次の単価レンジに到達するためのヒントも確認できます。