Zephir 算是一個新的高階語言,這個語言目前的作用就是為了要讓開發 PHP Extension 變得更簡單,其運作方式很簡單,就是將 Zephir Code 轉換為等效的 C 語言 Code,然後可以編譯成 PHP Extension。
目前一些特性(引述官方網站)
- 變數的型別上同時支援動態或強型別。
- 安全的記憶體管理,指標或直接記憶體存取是不允許的。
- 編譯模型 : ahead of time (其實我看不懂)
- 記憶體模型 : task-local garbage collection(其實我目前也不懂所為何)
我看過官方網站的一些文件,簡單來說,他的語法就是很高階了啦,且非常像PHP語法,原本寫 php extension,要用 C 語言搭配文件不足的 Zend Engine API 來寫,現在有了高階的語法寫完之後可以轉換成 C 語言再編譯成 php extension。
這麼做的好處我自個兒想的有 :
- 開發快速及程式碼易讀
- 可以使用 PHP 現有的 function
- 容易將現有的 PHP Code 移植為 Zephir Code,因為語法很像。
- 可以將特定功能轉為 Zephir 做到隱藏原始碼以達商業目的。
下面一段影片可以看到是怎麼開發的。
Creating your first PHP extension with Zephir from Phalcon Framework on Vimeo.
CentOS 下的安裝方法
撰寫本文時 zephir 是 0.3 版,日後應該變動挺大的
官方網站上寫安裝方式 在 Ubuntu 的必要的套件必須要有 :
- gcc >= 4.x/clang >= 3.x
- re2c 0.13 or later
- gnu make 3.81 or later
- autoconf 2.31 or later
- automake 1.14 or later
- libpcre3
- php development headers and tools
但我要介紹的是 CentOS 6,我自己發現還要安裝
- file
- libtool
- json-c-devel (官方採用 git 下載來裝,但 CentOS EPEL Repo 有內建)
這些在 CentOS 6 中使用下列命令來安裝即可
yum --enablerepo=remi install gcc re2c make autoconf php-devel file libtool json-c-devel.x86_64 json-c-devel.i686
接著用 git 下載 zephir 回來安裝 :
git clone https://github.com/phalcon/zephir cd zephir ./install -c
到這裡打住,照官方說明,因為要執行 ./install -c 後就會安裝,而我目前下載下來的版本發現會出錯,如以下錯誤訊息 :
[root@www zephir]# ./install -c Parser statistics: 110 terminals, 85 nonterminals, 347 rules 715 states, 0 parser table entries, 0 conflicts /usr/bin/ld: cannot find -ljson-c collect2: ld 回傳 1
原因可能是 install 內有一行寫得出問題,原本 install 內有一行是
gcc -Wl,-rpath /usr/local/lib -I/usr/local/lib -L/usr/local/lib -L/opt/local/lib -g3 -w parser.c scanner.c -ljson -ljson-c -o ../bin/zephir-parser
這行中必須將 -ljson-c 拿掉,變為如下
gcc -Wl,-rpath /usr/local/lib -I/usr/local/lib -L/usr/local/lib -L/opt/local/lib -g3 -w parser.c scanner.c -ljson -o ../bin/zephir-parser
修改完後存檔,然後再執行 ./install -c 即可
安裝成功後,執行 zephir ,若出現以下畫面則代表 zephir 順利完成安裝了
[root@www zephir]# zephir _____ __ _ /__ / ___ ____ / /_ (_)____ / / / _ \/ __ \/ __ \/ / ___/ / /__/ __/ /_/ / / / / / / /____/\___/ .___/_/ /_/_/_/ /_/ Zephir version 0.3.0a Usage: command [options] Available commands: version Shows Zephir version clean Cleans the generated object files in compilation generate Generates C code from the Zephir code compile Compile a Zephir extension fullclean Cleans the generated object files in compilation init [namespace] Initializes a Zephir extension install Installs the extension (requires root password) help Displays this help build Generate/Compile/Install a Zephir extension Options: -fno-([a-z0-9\-]+) Setting options to Compiler -W([a-z0-9\-]+) Setting warning options to Compiler
用zephir建立一個計算費氏係數的extension
費氏係數的範例一直是很多語言用來說嘴PHP效能的範例,我們現在用 zephir 寫個 extension,寫完後用 zephir 版本和原生PHP版本比較一下效能。
首先用 zephir 建立一個空的專案,名稱叫 benchmark,這個名稱預設也會是該 extension 的 namespace
zephir init benchmark
接著會看到 benchmark 文件夾被建立了,裡頭就是一個空專案了,然後會看到一些結構
drwxr-xr-x 4 root root 4096 2014-02-03 21:45 . drwxr-xr-x 3 root root 4096 2014-02-03 21:22 .. drwxr-xr-x 2 root root 4096 2014-02-03 21:27 benchmark -rw-r--r-- 1 root root 1232 2014-02-03 20:56 config.json drwxr-xr-x 8 root root 4096 2014-02-03 21:44 ext
這個benchmark 文件夾還有個 benchmark 文件夾,我們要寫的 zephir code 都是放這的。
現在寫一段 Code 放入 benchmark 文件夾,文件名稱為 Test.zep,Code 內容如下。
namespace benchmark; class Test { public static function fibonacci( n ) { var fibs,i; let fibs = [0,1]; for i in range(2,n) { let fibs[i] = fibs[i - 1] + fibs[i - 2]; } return fibs; } public static function strong_type_fibonacci( int n ) -> array { var fibs; int i; let fibs = [0,1]; for i in range(2,n) { let fibs[i] = fibs[i - 1] + fibs[i - 2]; } return fibs; } }
這段 Code ,如果真的會 PHP 的人應該不難懂吧,裡頭實作了兩個版本費氏係數,第一個用動態變數來演算,第二個則用強型變數來演算,接下來,我們於專案文件夾的路徑下執行 zephir build 進行編譯
如果編譯沒問題會出現如下
[root@www benchmark]# zephir build Compiling... Installing... Extension installed! Add extension=benchmark.so to your php.ini Don't forget to restart your web server
上面有提示別忘了把 extension=benchmark.so 加到 php.ini,不過我只是要測試就不加了,等下直接用 CLI 命令來載入,測試這個 extension 前我再寫一個 PHP 版的費氏係數(其實 Zephir 版的就是由這個 PHP 版的 Copy 去改的啦)並且加上和上面 Zephir 提供的兩種方式比較效能,Code 如下 ;
<?php class PurePHP { final static function fibonacci($n) { $fibs = array(0, 1); for ($i = 2; $i < $n; $i++) { $fibs[$i] = $fibs[$i - 1] + $fibs[$i - 2]; } return $fibs; } } $start = microtime(true); $results = array(); for($i=0; $i<50000; $i++) { $results = PurePHP::fibonacci(100); } $end = microtime(true); printf("PurePHP Results: %s\n" , implode($results,",")); printf("Time: %f\n" , $end - $start); // benchmark zephir $start = microtime(true); $results = array(); for($i=0; $i<50000; $i++) { $results = \benchmark\Test::fibonacci(100); } $end = microtime(true); printf("Zephir Results: %s\n" , implode($results,",")); printf("Time: %f\n" , $end - $start); // benchmark zephir strong type $start = microtime(true); $results = array(); for($i=0; $i<50000; $i++) { $results = \benchmark\Test::strong_type_fibonacci(100); } $end = microtime(true); printf("Zephir Strong Type Results: %s\n" , implode($results,",")); printf("Time: %f\n" , $end - $start);
這段 Code 測試了純 PHP 及剛剛寫的兩個 Zephir 的費氏係數,執行的結果如下 :
php -dextension=benchmark.so benchmark.php PurePHP Results: 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,1.2200160415122E+19,1.9740274219868E+19,3.194043463499E+19,5.1680708854858E+19,8.3621143489848E+19,1.3530185234471E+20,2.1892299583456E+20 Time: 1.101630 Zephir Results: 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,1.2200160415122E+19,1.9740274219868E+19,3.194043463499E+19,5.1680708854858E+19,8.3621143489848E+19,1.3530185234471E+20,2.1892299583456E+20,3.5422484817926E+20 Time: 0.609424 Zephir Strong Type Results: 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,1.2200160415122E+19,1.9740274219868E+19,3.194043463499E+19,5.1680708854858E+19,8.3621143489848E+19,1.3530185234471E+20,2.1892299583456E+20,3.5422484817926E+20 Time: 0.502283
這結果有點亂,反正三種測試所花的時間分別是
- 原生 PHP :1.101630 秒
- Zephir 動態變數演算 : 0.609424
- Zephir 強型變數演算 : 0.502283
這樣的結果確實可以看出 Zephir 真的對 PHP 效能有非常大的助益啊。
最後心得
其實 Zephir 語法不難學,我寫這個範例其實一開始碰到一些問題,Zephir 的變數全部要先用 var 或固定型別定義才能用,有點類似 C 語言的定義方法,習慣了之後,如果重寫這個範例,我想應該不用五分鐘吧,五分鐘就可以弄出一個高效的 extension,值得推廣的。
參考連結