PHP は分析用高級言語です。実際、Zend カーネルの観点から見ると、PHP は通常の C プログラムです。メイン関数があります。私たちが作成する PHP コードは、このプログラムの入力であり、その後、カーネルは結果を処理して出力します。カーネルが PHP コードを認識可能な C プログラムに「変換」するプロセスが PHP のコンパイルです。
推奨コース: PHP チュートリアル
C プログラムは、コンパイル中にコード行をマシンコードにコンパイルし、各操作は機械命令の場合、これらの命令はコンパイルされたバイナリプログラムに書き込まれ、実行時にはバイナリプログラムが対応するメモリ領域(定数領域、データ領域、コード領域)にロードされ、実行スタックが確保され、コード領域から開始されます。 . 開始位置から実行を開始します。これは、C プログラムのコンパイルと実行の単純なプロセスです。
同様に、PHP のコンパイルは通常の C プログラムのコンパイルと似ていますが、PHP コードがマシン コードにコンパイルされず、複数のオペコード配列に解析される点が異なります。各オペコードは C の通常の構造体であり、プログラムの機械語命令の実行プロセスは、エンジンがオペコードを順番に実行することです。たとえば、PHP で変数を定義します: $a = 123;
。カーネルでの実行は、メモリの一部を割り当てて、そこに値を書き込むことです。
zend_compile.h ファイルのオペコード構造:
struct _zend_op { const void *handler; //对应执行的C语言function,即每条opcode都有一个C function处理 znode_op op1; //操作数1 znode_op op2; //操作数2 znode_op result; //返回值 uint32_t extended_value; uint32_t lineno; zend_uchar opcode; //opcode指令 zend_uchar op1_type; //操作数1类型 zend_uchar op2_type; //操作数2类型 zend_uchar result_type; //返回值类型 };
したがって、PHP の解析プロセスのタスクは、PHP コードを (字句解析 re2c、構文解析 bison を通じて) オペコードに変換することです。コード内の配列 すべての情報はオペコードに保存され、オペコード配列は実行のために zend エンジンに渡されます オペコードは、代入、加算、減算演算、関数など、カーネルによって実行される特定のコマンドです各オペコードは処理ハンドルに対応しており、これらのハンドラはあらかじめ定義された C 関数です。
struct _zend_op_array { //common是普通函数或类成员方法对应的opcodes快速访问时使用的字段 /* Common elements */ zend_uchar type; zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; zend_function *prototype; uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; /* END of common elements */ uint32_t *refcount; uint32_t last; //opcode指令数组 zend_op *opcodes; //PHP代码里定义的变量数:op_type为IS_CV的变量,不含IS_TMP_VAR、IS_VAR的 //编译前此值为0,然后发现一个新变量这个值就加1 int last_var; //临时变量数:op_type为IS_TMP_VAR、IS_VAR的变量 uint32_t T; //PHP变量名数组 zend_string **vars;//这个数组在ast编译期间配合last_var用来确定各个变量的编号,非常重要的一步操作 int last_live_range; int last_try_catch; zend_live_range *live_range; zend_try_catch_element *try_catch_array; //静态变量符号表:通过static声明的 /* static variables support */ HashTable *static_variables; zend_string *filename; uint32_t line_start; uint32_t line_end; zend_string *doc_comment; uint32_t early_binding; /* the linked list of delayed declarations */ //字面量数量 int last_literal; //字面量(常量)数组,这些都是在PHP代码定义的一些值 zval *literals; //运行时缓存数组大小 int cache_size; //运行时缓存,主要用于缓存一些znode_op以便于快速获取数据,后面单独介绍这个机制 void **run_time_cache; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; };
opcode 命令: つまり、バイナリ プログラムのコード セグメントに対応する、PHP コードに対応する特定の処理アクション
リテラル ストレージ: PHP コードで定義された変数のいくつかの初期値、呼び出される関数の名前、クラス名、定数名などをリテラルといいます。これらの値は、実行中に変数や関数呼び出しなどを初期化するために使用されます。
変数の割り当て: リテラルと同様、これは、現在のオペコードによって定義されている変数と一時変数の数を指します。各変数には対応する番号があります。初期化は、合計数に応じて一度に zval を割り当てるために実行されます。使用されるときは、番号に応じてインデックスも付けられます
PHP コードからオペコードまで実装するにはどうすればよいですか?
最も簡単に考えられる方法は通常のマッチングですが、もちろんプロセスはそれほど単純ではありません。 PHP のコンパイル プロセスには、re2c と bison を使用して完了する字句解析と構文解析が含まれます。古い PHP バージョンでは、オペコードが直接生成されます。PHP7 では、新しい抽象構文ツリー (AST) が追加されます。AST は構文解析段階で生成され、その後、オペコード配列が生成されます
以上がphpファイルをコンパイルする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。