56-関数の内部構造
6511 ワード
56-関数の内部構造
PHPでは、関数には独自の役割ドメインがあり、その内部で様々な文の実行を実現し、最終結果値を返すことができます.PHPのソースコードでは、PHPカーネルが関数を次のタイプに分類していることがわかります.
その中のZEND_USER_FUNCTIONはユーザー関数、ZEND_INTERNAL_FUNCTIONは内蔵の関数です.つまりPHPは内蔵の関数とユーザ定義の関数を別々に保存する.
ユーザ関数(ZEND_USER_FUNCTION)
ユーザー定義関数は、次のコードのような一般的な関数の種類です.ユーザー定義関数を定義します.
この例では、カスタム関数にパラメータを入力し、Hi!一緒に出力して戻り値として返します.この例から、関数の基本的な特徴がわかります.実行時宣言、パラメータの伝達、値の戻りです.もちろん、いくつかの関数はいくつかの操作を行うだけで、必ずしも明示的に戻り値があるわけではありません.PHPの実装では、明示的な戻りがなくても、PHPカーネルは「NULLを返す」ことができます.
ZE実行中は、実行時情報が_に格納されるzend_execute_dataでは:
プログラムの初期化中にfunction_stateも初期化しますfunction_stateは2つの部分で構成されています.
**argumentsは関数パラメータを指すポインタであり、関数体自体は*functionに格納され、*functionはzend_である.function構造体は、最終的にユーザー定義関数のすべての情報を格納します.その具体的な構造は次のとおりです.
zend_functionの構造におけるop_arrayはその関数のすべての動作を記憶し、関数が呼び出されるとZEはこのop_をarrayのoplineの1つのバーが順次実行され、最後の戻り値が返されます.VLD拡張で見た関数に関する情報を見ると、関数の定義と実行は別々であり、1つの関数は独立した実行ユニットとして存在することができる.
内部関数(ZEND_INTERNAL_FUNCTION)
ZEND_INTERNAL_FUNCTION関数は、拡張またはZend/PHPカーネルによって提供され、「C/C++」で記述され、直接実行可能な関数です.内部関数の構造は次のとおりです.
最も一般的な動作は、モジュールの初期化時にZEがロードされた拡張モジュールごとに巡回し、モジュール内のfunction_entryで指定した各関数(module->functions)は、zend_を作成します.internal_function構造、typeをZEND_に設定INTERNAL_FUNCTIONは、この構造をグローバルな関数テーブル(HashTable構造)に埋め込む.関数の設定および登録手順はZend/zend_を参照してください.API.cファイルのzend_register_functions関数.この関数は関数を処理する以外に、クラスの方法も処理して、あれらのマジックの方法を含みます.
内部関数の構造はユーザーがカスタマイズした関数の構造と基本的に似ており、いくつかの違いがあります.
変数関数
PHPは変数関数の概念をサポートする.これは、変数名の後にカッコが付いている場合、PHPは変数の値と同じ名前の関数を探し、実行しようとすることを意味します.それ以外に,これはコールバック関数,関数テーブルなどを実現するために用いることができる.変数関数と内部関数を使用した呼び出しを比較します.
変数関数$func
VLDを使用して、このコードをコンパイルした中間コードを表示します.
内部関数print_r
VLDを使用して、このコードをコンパイルした中間コードを表示します.
比較すると,両者は呼び出した中間コードにいくつかの違いがあることが分かった.変数関数はDO_FCALL_BY_NAME、内部関数はDO_FCALL. これは文法解析で決定されましたZend/zend_を参照してください.complie.cファイルのzend_do_end_function_コール関数の一部のコード:
メソッドではなく、動的呼び出しではなく、関数名が文字列定数である場合、その生成する中間コードはZEND_であるDO_FCALL.その他の場合はZEND_DO_FCALL_BY_NAME. また、変数関数をコールバック関数として、Zend/zend_で処理します.complie.cファイルのzend_do_pass_param関数で.最終的には中間コード実行中のZEND_SEND_VAL_SPEC_CONST_HANDLERなどの関数にあります.
匿名関数
匿名関数は、シンボルを指定する必要がなく、呼び出される関数またはサブルーチンであり、匿名関数はパラメータとして他の関数に容易に渡すことができる.
PHPでは、関数には独自の役割ドメインがあり、その内部で様々な文の実行を実現し、最終結果値を返すことができます.PHPのソースコードでは、PHPカーネルが関数を次のタイプに分類していることがわかります.
#define ZEND_INTERNAL_FUNCTION 1
#define ZEND_USER_FUNCTION 2
#define ZEND_OVERLOADED_FUNCTION 3
#define ZEND_EVAL_CODE 4
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
その中のZEND_USER_FUNCTIONはユーザー関数、ZEND_INTERNAL_FUNCTIONは内蔵の関数です.つまりPHPは内蔵の関数とユーザ定義の関数を別々に保存する.
ユーザ関数(ZEND_USER_FUNCTION)
ユーザー定義関数は、次のコードのような一般的な関数の種類です.ユーザー定義関数を定義します.
<?php
function nowamagic( $name ){
$return = "Hi! " . $name;
echo $return;
return $return;
}
?>
この例では、カスタム関数にパラメータを入力し、Hi!一緒に出力して戻り値として返します.この例から、関数の基本的な特徴がわかります.実行時宣言、パラメータの伝達、値の戻りです.もちろん、いくつかの関数はいくつかの操作を行うだけで、必ずしも明示的に戻り値があるわけではありません.PHPの実装では、明示的な戻りがなくても、PHPカーネルは「NULLを返す」ことができます.
ZE実行中は、実行時情報が_に格納されるzend_execute_dataでは:
struct _zend_execute_data {
//...
zend_function_state function_state;
zend_function *fbc; /* Function Being Called */
//...
};
プログラムの初期化中にfunction_stateも初期化しますfunction_stateは2つの部分で構成されています.
typedef struct _zend_function_state {
zend_function *function;
void **arguments;
} zend_function_state;
**argumentsは関数パラメータを指すポインタであり、関数体自体は*functionに格納され、*functionはzend_である.function構造体は、最終的にユーザー定義関数のすべての情報を格納します.その具体的な構造は次のとおりです.
typedef union _zend_function {
zend_uchar type; /* #define ZEND_USER_FUNCTION 2
MUST be the first element of this struct! */
struct {
zend_uchar type; /* never used */
char *function_name; //
zend_class_entry *scope; //
zend_uint fn_flags; // , ZEND_ACC_STATIC
union _zend_function *prototype; //
zend_uint num_args; //
zend_uint required_num_args; //
zend_arg_info *arg_info; //
zend_bool pass_rest_by_reference;
unsigned char return_reference; //
} common;
zend_op_array op_array; //
zend_internal_function internal_function;
} zend_function;
zend_functionの構造におけるop_arrayはその関数のすべての動作を記憶し、関数が呼び出されるとZEはこのop_をarrayのoplineの1つのバーが順次実行され、最後の戻り値が返されます.VLD拡張で見た関数に関する情報を見ると、関数の定義と実行は別々であり、1つの関数は独立した実行ユニットとして存在することができる.
内部関数(ZEND_INTERNAL_FUNCTION)
ZEND_INTERNAL_FUNCTION関数は、拡張またはZend/PHPカーネルによって提供され、「C/C++」で記述され、直接実行可能な関数です.内部関数の構造は次のとおりです.
typedef struct _zend_internal_function {
/* Common elements */
zend_uchar type;
char * function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
/* END of common elements */
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
struct _zend_module_entry *module;
} zend_internal_function;
最も一般的な動作は、モジュールの初期化時にZEがロードされた拡張モジュールごとに巡回し、モジュール内のfunction_entryで指定した各関数(module->functions)は、zend_を作成します.internal_function構造、typeをZEND_に設定INTERNAL_FUNCTIONは、この構造をグローバルな関数テーブル(HashTable構造)に埋め込む.関数の設定および登録手順はZend/zend_を参照してください.API.cファイルのzend_register_functions関数.この関数は関数を処理する以外に、クラスの方法も処理して、あれらのマジックの方法を含みます.
内部関数の構造はユーザーがカスタマイズした関数の構造と基本的に似ており、いくつかの違いがあります.
,handler . ZEND_INTERNAL_FUNCTION, ZE zend_execute_internal, zend_internal_function.handler 。 , 。
module , 。 。
type , ,type , type 。
変数関数
PHPは変数関数の概念をサポートする.これは、変数名の後にカッコが付いている場合、PHPは変数の値と同じ名前の関数を探し、実行しようとすることを意味します.それ以外に,これはコールバック関数,関数テーブルなどを実現するために用いることができる.変数関数と内部関数を使用した呼び出しを比較します.
変数関数$func
$func = 'print_r';
$func('i am print_r function.');
VLDを使用して、このコードをコンパイルした中間コードを表示します.
function name: (null)
number of ops: 9
compiled vars: !0 = $func
line # * op fetch ext return operands
--------------------------------------------------------------------------------
-
2 0 > EXT_STMT
1 ASSIGN !0, 'print_r'
3 2 EXT_STMT
3 INIT_FCALL_BY_NAME !0
4 EXT_FCALL_BEGIN
5 SEND_VAL 'i+am+print_r+function.'
6 DO_FCALL_BY_NAME 1
7 EXT_FCALL_END
8 > RETURN 1
内部関数print_r
print_r('i am print_r function.');
VLDを使用して、このコードをコンパイルした中間コードを表示します.
function name: (null)
number of ops: 6
compiled vars: none
line # * op fetch ext return operands
--------------------------------------------------------------------------------
-
2 0 > EXT_STMT
1 EXT_FCALL_BEGIN
2 SEND_VAL 'i+am+print_r+function.'
3 DO_FCALL 1 'print_r'
4 EXT_FCALL_END
5 > RETURN 1
比較すると,両者は呼び出した中間コードにいくつかの違いがあることが分かった.変数関数はDO_FCALL_BY_NAME、内部関数はDO_FCALL. これは文法解析で決定されましたZend/zend_を参照してください.complie.cファイルのzend_do_end_function_コール関数の一部のコード:
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
opline->opcode = ZEND_DO_FCALL;
opline->op1 = *function_name;
ZVAL_LONG(&opline->op2.u.constant, zend_hash_func(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name->u.constant) + 1));
} else {
opline->opcode = ZEND_DO_FCALL_BY_NAME;
SET_UNUSED(opline->op1);
}
メソッドではなく、動的呼び出しではなく、関数名が文字列定数である場合、その生成する中間コードはZEND_であるDO_FCALL.その他の場合はZEND_DO_FCALL_BY_NAME. また、変数関数をコールバック関数として、Zend/zend_で処理します.complie.cファイルのzend_do_pass_param関数で.最終的には中間コード実行中のZEND_SEND_VAL_SPEC_CONST_HANDLERなどの関数にあります.
匿名関数
匿名関数は、シンボルを指定する必要がなく、呼び出される関数またはサブルーチンであり、匿名関数はパラメータとして他の関数に容易に渡すことができる.