使用Zephir開發PHP擴展

是什麼?

Zephir,一種開源的高級語言,旨在簡化PHP擴展的創建和可維護性,重點關注類型和內存安全性。

PHP框架(擴展)Phalcon團隊爲了更方便的開發,同時維護了zephir項目,並在Phalcon的v2-v4版本中應用。可惜2020年中,zephir主要維護者Serghei離開後,Phalcon宣佈v5版本將使用原生PHP開發。此後Zephir再沒有大的更新,除2021年3月發佈v0.13兼容PHP8,其它就是一些維護類的更新。

https://blog.phalcon.io/post/the-future-of-phalcon

當前最新release版本爲 0.15,但文檔版本僅更新到 0.12,參考:

https://docs.zephir-lang.com/0.12/en/welcome

小知識:

Zephir 這個名字是單詞 z (end) e (ngine)/ph (p)/i (nte) r (mediate) 的收縮。官方建議讀作zephyr,而他的創造者實際把它讀作zaefire。

爲什麼?

使用zephir有幾個好處:

  • 性能提升: 將一些不常變化的類庫編譯爲擴展,避免每次請求都重新加載執行,浪費CPU; 另外zephir會將代碼轉換爲PHP標準的C代碼擴展,編譯器在編譯擴展時會做一些優化;

  • 開發簡單: 相比直接使用C開發PHP擴展,以一種類似PHP語法的方式編寫,大大提升開發效率;

  • 代碼保護: PHP是解釋型語言,通常是直接暴露源代碼; 通過擴展方式發佈,可以隱藏原始代碼。對於發行軟件可以保護知識產權;對於自研系統,可以避免敏感信息泄露,提升安全性;

當然,使用zephir的一些注意:

  • 應該僅將需要優化性能或者保護信息的部分代碼改寫,因爲zephir的開發效率弱於比直接使用PHP;

  • 使用zephir開發擴展,相比純PHP系統,增加了項目開發,部署和維護成本;

  • 因爲擴展生命週期是進程級別,現在發佈代碼可能需要重啓php-fpm;

  • zephir項目生態上最主要的使用者Phalcon已經棄用,目前僅處於維護狀態,未來有擱淺風險;

總的說來,zephir適合的應用場景較窄,請謹慎選擇!

怎麼做?

版本選擇

0.13及之後版本只支持PHP7.4和PHP8, 0.12支持PHP7.2 - PHP7.4,可以按需要選擇。實際開發大同小異,本文以0.12爲例,環境爲 centos 7 + php7.3。

安裝

安裝zephir:

zephir提供了打包好的phar文件,直接下載使用即可:

wget https://github.com/zephir-lang/zephir/releases/download/0.12.21/zephir.phar
# 提供一個tx雲cos地址:https://public-pkg-1252772859.cos.ap-guangzhou.myqcloud.com/hyperf-box/zephir-v0.12.21.phar

chmod 755 zephir.phar
ln -s /usr/local/bin/zephir zephir.phar

# 查看是否安裝成功
zephir -v

zephir編譯代碼時需要使用zephir-parser擴展。安裝:

# 安裝編譯環境(按需)
sudo yum install php-devel gcc make re2c autoconf automake

# 說明: zephir-parser最新版是 v1.4.1,但該版本與 zephir 0.12不兼容
wget https://github.com/zephir-lang/php-zephir-parser/archive/refs/tags/v1.3.8.tar.gz -O zephir-parser.tgz
# 同樣提供一個tx雲cos地址: https://public-pkg-1252772859.cos.ap-guangzhou.myqcloud.com/hyperf-box/php-zephir-parser-1.3.8.tar.gz
tar zxvf zephir-parser.tgz
cd php-zephir-parser-1.3.8/
# 注意根據實際地址修改 phpize 和 php-config 路徑
/usr/local/bin/phpize
./configure --with-php-config=/usr/local/bin/php-config
make
sudo make install

# 在 php.ini 中啓用擴展
[zephir parser]
extension=zephir_parser.so

# 測試(說明:此版本擴展名稱是 Zephir Parser;v1.4.1 起擴展名稱改爲了 zephir_parser
/usr/local/bin/php -m | grep -i zephir
/usr/local/bin/php --ri "zephir parser"

安裝中細節有疑問的,可以參考官方文檔:

https://docs.zephir-lang.com/0.12/en/installation

https://github.com/zephir-lang/php-zephir-parser

開發

hello world:

# 創建環境
zephir init demo
cd demo
ls
# config.json  demo  ext
# 有2個目錄: ext 是生成擴展的代碼; demo(與項目同名)目錄是編碼的地方
# 還有一個 config.json 的文件。可以使用配置,更改 Zephir 和/或擴展本身的行爲


# 創建類
cat > demo/Hello.zep
namespace Demo;

class Hello
{

    public static function say(string name="world")
    {
        echo "hello ".name."!\n";
    }
}

# 生成擴展代碼
zephir generate
# vim ext/demo/hello.zep.c  可以查看生成的C代碼


# 編譯安裝同標準php擴展,略

# 測試
php -r "Demo\Hello::say('zephir');"

語法學習:

zephir的語法不復雜,有一點像 php + js 結合體,詳細見:

https://docs.zephir-lang.com/0.12/en/language

一些注意:

  • 在 zephir 中,每個文件都必須包含且僅包含一個類。每個類都必須有一個命名空間,並且目錄結構必須與所使用的類和命名空間的名稱相匹配。

  • zephir可以使用PHP內置的各種函數; 甚至還可以使用運行時存在的用戶自定義函數和超全局變量等。

  • 函數參數即使指定了類型,也不會強校驗,只是會嘗試轉化類型;如上面例子執行 php -r "Demo\Hello::say(123);" 依然可以正常出結果 。如果需要強制校驗,需要在參數後面追加一個歎號(!)。

高級技巧:

編譯配置:

https://docs.zephir-lang.com/0.12/en/config

PHP生命週期事件鉤子:

https://docs.zephir-lang.com/0.12/en/lifecycle

擴展練習:

我們可以嘗試一下zephir編寫一個微型PHP框架擴展,僅包含:配置文件加載(Config類),日誌文件記錄(Logger類)和數據庫查詢(Db類)。

詳見項目: https://gitee.com/dingusxp/zephir-hellophp

經驗

使用zephir改造PHP代碼還是很簡單的。先寫PHP代碼,再照以下步驟轉化:

  1. 字符串單引號替換爲雙引號;

  2. 變量去掉 $ 符號;

  3. 變量預定義,使用 var 或者具體類型(int/string/array等);

  4. 變量賦值語句前面加上 let;

  5. for循環語句轉換爲loop,參考: foreach ($data as $key => $value) => for (key, value in data)for ($i = 0; $i < 10; $i++) => loop (i in range(0, 9))

  6. 異常捕捉語句修改,參考: catch (Exception $e) => catch Exception, e

  7. 一般以上步驟完成已經改的七七八八了; 接下來直接執行 zephir generate嘗試生成擴展(一般不會這麼順利),並按提示修改代碼。

Phalcon的v4最後發行版還是使用zephir,可以學習其源碼:

https://github.com/phalcon/cphalcon/tree/4.1.2-release/phalcon

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章