PHP Mailing Lists 上這兩天有個好玩兒的問題:Introduction to the PHP source code,大概就是有人想知道如何學習 PHP 原始碼,可是這種事情不是應該自己去發掘的嗎?
上面是玩笑話,現在我也說說如何學習 PHP 直譯器的原始碼。
首選你要知道的是 PHP 直譯器原始碼的 github 地址:https://github.com/php/php-src ,話說回來還有人不知道嗎?這裡有幾乎所有 PHP 的程式碼提交記錄、pull requests 和一些 issue 等。
建立編譯指令碼或者釋出包
從 Branch 中選擇一個版本 tag,和每次 PHP 釋出出來的版本就是一致的。也許你會發現你想編譯的的時候缺找不到 configure
檔案,但是有 configure.in
檔案。這時候需要先執行的是 buildconf
(如果是在 Windows 下面可以執行 buildconf.bat
,不過我從來沒有嘗試過在 Windows 下面編譯 PHP,所以具體的步驟我就不清楚了)。buildconf 本身是個簡單的 shell 指令碼,你可以用記事本開啟看看它(最終的執行檔案在 build
目錄裡,這個目錄裡有一些與編譯有關的檔案)。
這裡面涉及到一個系列的編譯工具:Autotools。如果你有興趣,可以簡單的瞭解一下,沒有興趣的話也不用多考慮,因為這些工具絕大多數 Linux 系統上都是已經存在的。
如果你想將 Github 上的 PHP 原始碼做成一個可釋出的原始碼包,你可以看看 makedist
這個檔案,它也是一個 shell 指令碼(實際上原始碼裡幾乎所有跟編譯相關的指令碼都是 shell 指令碼)。但是如果想直接執行者這個指令碼,你可能會收到缺少以下元件的提示:re2c
和 Bison
。仔細看 makedist 的檔案,裡面有呼叫 genfiles
這個指令碼的語句,上面兩個工具就是在 genfiles 的指令碼里被呼叫的。
re2c 和 Bison 分別是 PHP 用到的詞法解析器和語法分析器。在 genfiles 這個檔案中可以看到它們的呼叫其實是在 Makefile.frag
中寫著,分別通過 zend_language_scanner.l
和 zend_language_parser.y
生成相應的 C 語言檔案(這個應該很多地方都有提到過)。
編譯直譯器並初始化
到了編譯環節,編譯之前需要先通過 configure
檔案生成 Makefile 然後執行 make
,所以 gcc
自然是必不可少的。configure 檔案本身也是一個 shell 指令碼,你也可以簡單閱讀一下它的內容。不過既然它是由 autoconf
從 configure.in
中生成的,也許直接檢視 configure.in 會更輕鬆一些。
到這裡總結一下就是:拋開一些核心擴充套件額依賴(比如 xml,ssl 等),編譯 PHP 的先決條件是機器上有 Autotools 的工具(automake,autoconf 等),需要安裝 re2c 和 Bison,當然還有編譯工具(gcc)。
也許大家都知道,使用 configure
生成 Makefile 的時候可以通過 --prefix
引數指定目錄,同時也可以選擇編譯哪些核心模組。至於哪些模組會被預設整合而哪些不會,這些本身是寫在每個擴充套件的 config.m4
(也有幾個是被命名為 config0.m4 或 config9.m4)檔案裡的的,全都通過一些 --enable
、--disable
、--with
和 --without
的選項來控制。
編譯的也與你採用的 Web 伺服器有關,這涉及到你需要使用哪個 sapi
,如果是 Apache,也許需要指定 --with-apxs2
的引數,如果是 Nginx,php-fpm
在預設條件下是會被編譯的,但可以指定 php-fpm 的執行組和使用者,不過這個是可以在編譯完成後在配置中修改的。
編譯完成之後還有一些事情需要考慮,最基本的問題是 PHP 的配置檔案的問題,還有一個是如果使用的是 php-fpm,如何更便捷的控制它的啟動、停止以及重啟等。
在 PHP 原始碼根中已經準備了兩份配置檔案的模板:php.ini-development
和 php.ini-production
。顯然是分別用於開發環境和生產環境的,將其中一個複製到配置檔案目錄並重新命名為 php.ini
即可(如果你不知道配置檔案的目錄在哪裡,可以使用 php --ini
命令檢視)。然後也可以根據你的需要修改它。
至於 php-fpm 的控制指令碼,原始碼中本身也是有提供的,在 sapi/fpm
目錄下。這個目錄下的幾個檔案中有 php-fpm 配置檔案的模板,也有稍微修改即可放到伺服器 /etc/init.d
目錄下用於控制 php-fpm 的 start
、stop
、restart
和 reload
動作的指令碼,現在的版本中也提供了用於 systemd
的 service 檔案。
擴充套件編譯
如果 PHP 編譯完成之後,發現還需要一些沒有編譯進去的核心擴充套件或者第三方擴充套件,你可以單獨編譯它們。
擴充套件編譯的整個過程一共四句命令:
-
phpize
-
./configure
-
make
-
make install
phpize
命令是用來準備 PHP 擴充套件庫的編譯環境的。在執行 phpize
的時候,如果有多個版本的 PHP,用哪個就要選哪個。這個命令和編譯後的 php 的二進位制檔案在同一個目錄中,也是一個 shell 指令碼。
執行 configure
的時候,如果當前 $PATH
中找不到 php-config
或者有多個版本的 PHP 時,也需要通過 --with-php-config
的指令來指定 php-config 的目錄。php-config 是一個用於獲取所安裝的 PHP 配置的資訊,它也一樣是和 php 的二進位制檔案在同一個目錄的 shell 指令碼。
phpize 和 php-config 的原始碼生成檔案都是在 scripts 目錄下。
所有工作完成之後,就可以愉快的使用你自己定製的 PHP 了。
原文地址:http://0x1.im