【ISSUE】[PHP7]エクステンションで自作関数を作る
2024年12月23日 17:28
Swiftとかだとextension
を使って、元から存在する型(String, arrayとか)に任意の関数を追加することができます。
しかし、PHPのエクステンションはC言語で書かれています。そのため実装は大変なのですが、普通のPHPスクリプトと異なり高速で動作します。このエクステンションはPHP7 と PHP5 で大幅に変わったらしいのですが、基本的には変わっていないように感じました。
ここでは、PHP7.1.2 をチェックアウトしていきます。
雛形をビルド/実行できるかを確認してみます
config.m4 を編集します。10行目あたりの
という箇所のコメントを外します。ここファイルでのコメントはdnl
で表されます。
なので、dnl
を消してください。
-d extension=./modueles/myext.so
で .so ファイルをロードして、 Congratulations! You have successfully 〜
という表示が出れば準備完了です。
今回は簡単なadd関数を自作することにします。add_extension
という関数名にしておきます。使用例としては
今回はconst zend_function_entry add_extension_functions[]
にadd_extension
関数を追加して行きます。変数名は特に指定されていないのでわかりやすくしておきましょう。
PHP_FE(add_extension, NULL)
の第2引数にarg_info
という構造体を渡すとタイプヒンティングやリフレクション等が利用できるようになります。この説明については付録で書きます。
関数本体を実装するときにはPHP_FUNCTION()
というマクロを利用します。
第1引数は最小引数、第2引数は最大引数の個数を表します。
受け取る引数の型を指定して、どの変数に代入するかを指定します。型指定子
とよばれ以下のように定義されています。
specifier | Fast ZPP API macro | args |
---|---|---|
| | Z_PARAM_OPTIONAL | |
a | Z_PARAM_ARRAY(dest) | dest - zval* |
A | Z_PARAM_ARRAY_OR_OBJECT(dest) | dest - zval* |
b | Z_PARAM_BOOL(dest) | dest - zend_bool |
C | Z_PARAM_CLASS(dest) | dest - zend_class_entry* |
d | Z_PARAM_DOUBLE(dest) | dest - double |
f | Z_PARAM_FUNC(fci, fcc) | fci - zend_fcall_info, fcc - zend_fcall_info_cache |
h | Z_PARAM_ARRAY_HT(dest) | dest - HashTable* |
H | Z_PARAM_ARRAY_OR_OBJECT_HT(dest) | dest - HashTable* |
l | Z_PARAM_LONG(dest) | dest - long |
L | Z_PARAM_STRICT_LONG(dest) | dest - long |
o | Z_PARAM_OBJECT(dest) | dest - zval* |
O | Z_PARAM_OBJECT_OF_CLASS(dest, ce) | dest - zval* |
p | Z_PARAM_PATH(dest, dest_len) | dest - char*, dest_len - int |
P | Z_PARAM_PATH_STR(dest) | dest - zend_string* |
r | Z_PARAM_RESOURCE(dest) | dest - zval* |
s | Z_PARAM_STRING(dest, dest_len) | dest - char*, dest_len - int |
S | Z_PARAM_STR(dest) | dest - zend_string* |
z | Z_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
とりあえず関数のエクステンションを作り上げることまではできるようになりました。
記事を書く気力とプログラムを組む気力があれば、エクステンションでクラス作成もしてみたいと思います。
PHP_FE
マクロの第2引数はReflection APIに対して関数の引数情報を提供するために使用されます。つまりは指定しなくても(NULL
でも)動きますが、実装したExtensionを後悔する場合には必ずと言っていいほど必要になるので、実装しておく方が無難です。以下にmb_convert_encoding
関数を例に示します。
この定義がされているphp/ext/mbstring/mbstring.c
には以下のように記載されています
以下の4つの引数を指定します。
引数番号 | 解説 |
---|---|
1 | 定義名(PHP_FEマクロの第2引数として指定する文字列) |
2 | 未使用 |
3 | 返却フラグ(1: 参照を返す, 0: 受け取るだけ) |
4 | 必須引数の個数 |
関数の引数の数だけ記述する必要があります。それぞれ以下の2つの引数を指定します。
引数番号 | 解説 |
---|---|
1 | 1: 参照渡し, 0: 値渡し |
2 | 仮引数名 |
引数定義の終了を示します。
先ほどのを見返すと
となっています。必須引数が2となっていますが、これはZEND_ARG_INFO
の定義順で必須になっていくので注意してください。また、ZEND_ARG_INFO
の第1引数が0なので全て値渡しになります。
このPHP_FE
やZEND_ARG_INFO
で行なった引数定義はReflectionFunction
クラスを用いて参照することができます
[cv:issue_marketplace_engineer]
診断を受けるとあなたの現在の業務委託単価を算出します。今後副業やフリーランスで単価を交渉する際の参考になります。また次の単価レンジに到達するためのヒントも確認できます。