PHP 開發者應該將 Zephir 列為重要觀察的專案

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 後就會安裝,而我目前下載下來的版本發現會出錯,如以下錯誤訊息 :

[[email protected] 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 順利完成安裝了

[[email protected] 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 進行編譯

如果編譯沒問題會出現如下

[[email protected] 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,值得推廣的。

參考連結

 

發表迴響