56-関数の内部構造

6511 ワード

56-関数の内部構造
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などの関数にあります.
匿名関数
匿名関数は、シンボルを指定する必要がなく、呼び出される関数またはサブルーチンであり、匿名関数はパラメータとして他の関数に容易に渡すことができる.