PHP のコア: ハッカーの手引き
PHP Manual

関数の作成

PHP では関数とメソッドはだいたい同じ形式で、メソッドは単にスコープが限定された関数でしかありません。 つまり、そのメソッドが属するクラスエントリのスコープになるということです。 クラスエントリについては、このマニュアルの別のページで説明します。 このセクションの目的は、関数やメソッドの内部構造を紹介することです。 関数を定義したり、変数を受け取ったり、PHP プログラマーに値を返したりする方法を説明します。

関数の内部構造は、それほど単純ではありません。

PHP_FUNCTION(hackers_function) {
  /* 受け取る引数をここで指定します */
  long number;
  
  /* 引数を受け取ります */
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &number) != SUCCESS) {
      return;
  }
  
  /* 何かの作業をします */
  number *= 2;
  
  /* 戻り値を設定します */
  RETURN_LONG(number);
}

プリプロセッサの PHP_FUNCTION(hackers_function) 命令は、 次のような宣言に展開されます。

void zif_hackers_function(INTERNAL_FUNCTION_PARAMETERS)

INTERNAL_FUNCTION_PARAMETERS はマクロとして定義されており、 次の表のようになります。

INTERNAL_FUNCTION_PARAMETERS
型と名前 説明 アクセス用マクロ
int ht ユーザーから実際に渡されたパラメータの数 ZEND_NUM_ARGS()
zval *return_value PHP 変数へのポインタ。ここに、ユーザーへの戻り値を設定します。 デフォルトの型は IS_NULL です。 RETVAL_*, RETURN_*
zval **return_value_ptr PHP に参照を返すときには、ここに変数へのポインタを設定します。 参照を返すことはお勧めしません。  
zval *this_ptr メソッド呼び出しの場合は、$this オブジェクトを保持する PHP 変数を指します。 getThis()
int return_value_used 返り値を呼び出し元が使うかどうかを示すフラグ。  

For clarity, the fully expanded declaration for PHP_FUNCTION(hackers_function) looks like:

void zif_hackers_function(int ht, zval* return_value, zval** return_value_ptr, zval* this_ptr, int return_value_used)

The precense of this_ptr may be confusing, classes are covered in detail in later sections, suffice to say that PHP_METHOD(MyClass, hackersFunction) would result in the following declaration:

void zim_MyClass_hackersFunction(INTERNAL_FUNCTION_PARAMETERS)

hackers_function doesn't do anything useful, it accepts a number using the zend_parse_parameters API, doubles it, and returns it to the engine. It is obvious that a normal function would have to do something more complex than double the input, for the purposes of education we are keeping it simple. On entry to the function return_value is allocated and initialized to null, making null the default return value of any function in PHP.

If zend_parse_parameters does not recieve what is specified by the Hacker as the correct arguments, and the arguments recieved cannot be converted to conform with type_spec an error will be raised, and by convention, the Hacker should return immediately.

注意:

Arrays, Objects, and Resources cannot be converted.

Parsing Parameters Prototypes
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...)
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...)
int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...)

注意:

zend_parse_parameter is available from version 5.5, it behaves like zend_parse_parameters_ex except that instead of reading the arguments from the stack, it receives a single zval to convert, which may be changed in place.

注意:

flags is intended to be a mask, currently only ZEND_PARSE_PARAMS_QUIET will have any impact (supress warnings)

The variable arguments recieved by these API functions are expected to be the address of C variables, and should be considered the output of the zend_parse_parameters API functions.

Type Specifiers
Spec Type Locals
a array zval*
A array or object zval*
b boolean zend_bool
C class zend_class_entry*
d double double
f function zend_fcall_info*, zend_fcall_info_cache*
h array HashTable*
H array or object HashTable*
l long long
L long (limits out-of-range LONG_MAX/LONG_MIN) long
o object zval*
O object (of specified zend_class_entry) zval*, zend_class_entry*
p string (a valid path) char*, int
r resource char*
s string char*, uint
z mixed zval*
Z mixed zval**

注意:

Where the type specifier is O, the local zend_class_entry* is to be considered input (part of the type spec) to zend_parse_parameter

Advanced Type Specifiers
Spec Description
* a variable number of argument of the preceeding type, 0 or more
+ a variable number of argument of the preceeding type, 1 or more
| indicates that the remaining parameters are optional
/ SEPARATE_ZVAL_IF_NOT_REF on the parameter it follows
! the preceeding parameter can be of the specified type or null For 'b', 'l' and 'd', an extra argument of type zend_bool* must be passed after the corresponding bool*, long* or double* addresses which will be set true if null is recieved.

注意:

Consult README.PARAMETER_PARSING_API included in source distributions for more information on parsing parameters

Once the Hacker's function has executed whatever it was implemented to execute, it is time to set the return_value for the engine. The RETURN_ and RETVAL_ macros are just wrappers around Z_*_P macros that work with return_value.

注意:

RETURN_ macros cause execution to leave the function immediately (ie: return;), while RETVAL_ macros allow execution to continue after return_value has been set.

The Hacker should now have a reasonable understanding of the anatomy of a function, and to some degree, the anatomy of a method.


PHP のコア: ハッカーの手引き
PHP Manual