萬事起頭難
我覺得因為有 c9s 整理重點、地雷和 skeleton 才會看起來比較簡單,但其實...這很不簡單!!
上次寫 c 大概在 7 年前了~
所以需要沉澱一下...
進入正題
進入正題
一些觀念
關於變數 (http://php.net/manual/en/internals2.variables.intro.php)"PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting."
所以有幾個重要的觀念要會
1. copy on write
2. reference counting
3. php 變數是沒有型態的,但實際在 c 語言中是使用 zval 這個 struct
typedef struct _zval_struct {
zvalue_value value; /* variable value */
zend_uint refcount__gc; /* reference counter */
zend_uchar type; /* value type */
zend_uchar is_ref__gc; /* reference flag */
} zval;
其中 zvalue_value 是下列 sturcttypedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len; /* this will always be set for strings */
} str; /* string (always has length) */
HashTable *ht; /* an array */
zend_object_value obj; /* stores an object store handle, and handlers */
} zvalue_value;
關於檔案結構 (http://php.net/manual/en/internals2.structure.files.php)
config.m4:configure 用的
// 這裡紅字部份就是在 ./configure --enable-foo 是相同的
PHP_ARG_ENABLE(foo, whether to enable foo extension support,
[--enable-foo Enable foo extension support])
// php_foo.c 是實作的檔案
if test $PHP_FOO != "no"; then
PHP_NEW_EXTENSION(foo, php_foo.c, $ext_shared)
fi
php_counter.c:自己的 extension 主程式 (說明是寫 counter.c 改成跟 h 同名,檔案多時比較知道是什麼)
PHP Life Cycle
https://fntlnz.github.io/php-extensions-development/#/3
http://www.phpxs.com/post/1039
第一個 Hello World
剛好最近在學習 Larvel 直接拿 homested 做環境 (什麼都不用安裝就能編譯)(是 vagrant,可以參考 http://laravel.tw/docs/5.1/homestead 自行安裝)
1. ssh 進 homested 後
2. 下載 c9s 整理好的 skeleton
git clone https://github.com/c9s/php-ext-skeleton3. 改一下程式
vi php_foo.c
改這裡,改成PHP_FUNCTION(foo_hello) { RETURN_STRING("Hello World", 1); }
4. 編譯
phpize ./configure --enable-foo make make install編好的會在 php-ext-skeleton/modules 目錄下
install 完的 .so 檔案會在 php default extension 目錄下 (這環境在 /usr/lib/php5/20131226/)
加入 php.ini 加入 extension
例如
echo "extension=foo.so" > /etc/php5/cli/conf.d/20-foo.ini
(這裡只有 cli 才會 work,請依自已的環境調整)5.執行看看
php -r "echo foo_hello();"
應該會顯示 Hello World寫測試
(https://qa.php.net/write-test.php)mkdir tests
vi tests/foo.phpt
寫入--TEST--
Check foo_hello
--FILE--
<?php
echo foo_hello();
--EXPECT--
Hello World
--TEST--
測試名稱
--FILE--
寫 php code
--EXPECT--
比對 echo 的資料
make test
GDB debug
(https://github.com/rcousens/packer-php7-dev/blob/master/doc/02-debug-php-extension.md)
實戰寫一個自己的 extension
(http://php.net/manual/en/internals2.funcs.php)實作一個 swap function
可以用 c9s 提的指令快速換內容
perl -i -pe 's/foo_hello/swap/g' config.m4 *.h *.c
perl -i -pe 's/foo/swap/g' config.m4 *.h *.c
perl -i -pe 's/Foo/Swap/g' config.m4 *.h *.c
perl -i -pe 's/FOO/SWAP/g' config.m4 *.h *.c
mv foo_hello.c swap.c
mv foo_hello.h swap.h
一般在 php 寫應該像這樣function swap(&$a, &$b) {
$tmp = $a;
$a = $b;
$b = $tmp;
}
C 應該是像這樣void swap(int *a, int *b) {
int tmp=*a;
*a=*b;
*b=tmp;
}
開始寫 swap.c 主要是改以下內容
PHP_FUNCTION(swap) {
zval *za = NULL;
zval *zb = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &za, &zb) == FAILURE) {
RETURN_FALSE;
}
zval tmp = *za;
*za = *zb;
*zb = tmp;
RETURN_TRUE;
}
1. zval 就是 php 的變數型態
因為要實作任何型態都能 swap 的 function 所以我使用 zval 宣告兩個指標變數 *za、*zb
2. PHP_FUNCTION(swap) 跟在程式開頭寫下面這段有關
static const zend_function_entry swap_functions[] = {
PHP_FE(swap, NULL)
PHP_FE(f1, NULL)
PHP_FE(f2, NULL)
PHP_FE_END
};
PHP_FE 是註冊在 php 時,call function namePHP_FUNCTION(swap) 的 swap 就是指在實作 swap 這個 function
如果是實作 f1那就是 PHP_FUNCTION(f1)
3. zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &za, &zb)
這行就是取得 php call function 時的參數
這裡跟 scanf 很像就是用 za 和 zb 接下來
然後 "zz" 就是接幾個參數和該參數型態,這裡用 zval
4. 取得參數後就是 swap 的主邏輯了
完整 Source:https://github.com/ffbli666/php-extension-examples
延伸思考和學習(研究ing)
- 如果只是 Function extension 和 hack 之間的差異?
這裡目前只講到 Function ,那如何寫 Class?(話說我以前也沒用 c 寫出 class 過)
(寫 class http://rpg1982.blogspot.tw/2015/11/php-php-extension-php-class.html)
- PHP 也有 Day #21 從 C 語言到 PHP Extension 錄影
- https://github.com/c9s/php-ext-skeleton
- https://fntlnz.github.io/php-extensions-development/#/
- http://www.walu.cc/phpbook/preface.md
- http://php.net/manual/en/internals2.php
- http://www.phpinternalsbook.com/index.html
- https://www.facebook.com/groups/849639948396465/permalink/1221426374551152/
- http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/
- http://stackoverflow.com/questions/1250412/how-do-i-build-my-first-php-extension-in-c-on-linux-gcc
- https://qa.php.net/write-test.php
- http://php.net/manual/en/internals2.variables.intro.php
- http://php.net/manual/en/internals2.structure.files.php
- http://php.net/manual/en/internals2.funcs.php
- http://www.phpxs.com/post/1039
- https://github.com/rcousens/packer-php7-dev/blob/master/doc/02-debug-php-extension.md
沒有留言:
張貼留言