PHPの内部構造について学ぼう①
普段は業務でPHPを触っている自称PHPエンジニアです。
PHPの内部構造もとい、Zend Engineの学習をします。
業務をただこなすだけだったら、正直学習する必要はないと思います。
私がZend Engineを学習する理由としては2つあります。
- プログラミング言語を自作してみたいから
- 裏側を知ることで、他のプログラミング言語の習得を容易にするため
プログラミング言語を自作するにあたって、PHPのZend Engineの
設計パターンなどを模倣しながら作っていこうと考えています。
そのため、Zend Engine を解析します。
PHPのソース→Zend Engine までの流れ
【PHP】Zend Engine の内部を図示した記事・資料まとめ - Qiitaはじめに C言語も英語も中国語も読めないPHP入門者です。 @tadsan さんの PHPの実行時とコンパイル時 を読んで、PHP内部でどのように処理されているのか全く理解していないことに気づきました。 理解するにはPHP内部のコードを読む...
学習にするにあったって、QiitaやGemini とともに進めました。

細かいところは省いていますが、大まかの流れとしてはこんな感じですね。
(私もまだ理解しきれていないところあります…)
PHP Script からOpcode
それでは実際にPHP→Opcode にコンパイルしたものを見てみましょう。(opcodeとは、PHPコードを機械が実行できる中間コードのことです。)
空のphpファイルを用意してコンソールで下記を実行
ZE-project % php -d opcache.enable_cli=1 -d opcache.opt_debug_level=0x10000 study.php
はい、↓がOpcode です。
$_main:
; (lines=1, args=0, vars=0, tmps=0)
; (before optimizer)
; /Users/sample/Desktop/ZE-project/study.php:1-1
; return [] RANGE[0..0]
0000 RETURN int(1)
では続いて、変数に3を代入してみましょう。
<?php
$a = 3;
echo $a;
$_main:
; (lines=3, args=0, vars=1, tmps=1)
; (before optimizer)
; /Users/sample/Desktop/ZE-project/study.php:1-3
; return [] RANGE[0..0]
0000 ASSIGN CV0($a) int(3)
0001 ECHO CV0($a)
0002 RETURN int(1)
Opcode にコンパイルされましたね。
0000 ASSIGN CV0($a) int(3) で int になってますね。
PHPで書くときは変数では型宣言はしないですよね。でも、Zend Engin で実行するときに型をチェックします。はい、動的型付けというものですね。この実行時にチェックなどをするために実行速度が他の言語と比べて遅かったりするらしいです。
こんな感じで Opcode がどんなものかを学習しました。
Zend VM について
正直私はC言語については少ししか触ったことないので、全く読めません。笑
なので、Opcode と C言語の関数がどのように紐づているのかを見ただけです。
Zend Engine のリポジトリからソースを落としてきて、分からないなりに眺めていました。笑
GitHub - php/php-src: The PHP InterpreterThe PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.
static zend_vm_opcode_handler_t const labels[] = {
(void*)&&ZEND_NOP_SPEC_LABEL,
(void*)&&ZEND_ADD_SPEC_CONST_CONST_LABEL,
(void*)&&ZEND_ADD_SPEC_CONST_TMPVARCV_LABEL,
(void*)&&ZEND_ADD_SPEC_CONST_TMPVARCV_LABEL,
(void*)&&ZEND_NULL_LABEL,
(void*)&&ZEND_ADD_SPEC_CONST_TMPVARCV_LABEL,
(void*)&&ZEND_ADD_SPEC_TMPVARCV_CONST_LABEL,
(void*)&&ZEND_ADD_SPEC_TMPVARCV_TMPVARCV_LABEL,
(void*)&&ZEND_ADD_SPEC_TMPVARCV_TMPVARCV_LABEL,
最後に
今回はPHPの内部構造について学習しました。今まで自分が浅いところにしかいなかったな、と思い知らされました。
PHPの内部構造についてはまだまだ学習していくつもりです。
そして、いつかは自作のプログラミング言語を作るつもりです!
(私が未熟ゆえ、今回の投稿記事も間違いがある場合がございます。ご指摘いただけますと幸いです。)


コメント