第一個有點作用的PHP擴展


C/C++去開發PHP擴展

我覺的對於PHP開發人員來說,學的東西非常雜,也非常多,當然了開發PHP擴展也是一個必須要掌握的技能,這里膜拜下大神鳥哥(Laruence)~
今天要開發的第一個有點功能的擴展,主要作用是記錄日志的時候生成日志前面的日期部分

#即使當前的時間,年-月-日 時:分:秒 時間戳.微妙數 
[2015-05-19 20:39:32 1432039172.968199]

php擴展函數前奏

首先生成”骨架“:
1. 進入php源碼src/ext目錄下面
2. 運行./ext_skel --extname=mytest
3. 進入src/ext/mytest/目錄
4. 在編寫擴展的時候要先修改下config.me文件的10-12行,去掉前面的dnl注釋,這個網上一搜一大把。
在頭文件php_mttest.h中聲明要編寫的php擴展函數名
PHP_FUNCTION(get_log_title);
#PHP_FUNCTION是PHP內核中聲明的一個宏
#define PHP_FUNCTION 		ZEND_FUNCTION    //在文件src/main/php.h : 347行
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))		//文件src/Zend/zend_API.h : 68行
#define ZEND_FN(name) 		zif_##name		//文件src/Zend/zend_API.h : 65行
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)	//文件src/Zend/zend_API.h : 67行
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC	//src/Zend/zend.h : 290行

上面的聲明函數宏展開后是:

void zif_get_log_title( int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC)
在mytest.c中的zend_function_entry聲明中添加get_log_title函數的聲明
const zend_function_entry logs_functions[] = {
        PHP_FE(confirm_logs_compiled,   NULL)           /* For testing, remove later. */
		PHP_FE(get_log_title, NULL)
        PHP_FE_END      /* Must be the last line in logs_functions[] */
};
#編寫函數
PHP_FUNCTION(get_log_title)
{
    struct timeval tv;
    time_t rawtime;
    struct tm *timeinfo;
    char *formatinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    gettimeofday(&tv, NULL);
    spprintf(&formatinfo, 0, "[%4d-%02d-%02d %d:%d:%d %d.%d]", 1900 + timeinfo->tm_year, 1 + timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, tv.tv_sec, tv.tv_usec);
    RETURN_STRING(formatinfo, 1);
}

這里還要看個宏RETURN_STRING

#define RETURN_STRING(s, duplicate) 	{ RETVAL_STRING(s, duplicate); return; }		//文件src/Zend/zend_API.h : 635行
#define RETVAL_STRING(s, duplicate) 	ZVAL_STRING(return_value, s, duplicate)			//文件src/Zend/zend_API.h : 623行
#define ZVAL_STRING(z, s, duplicate) do {	\	//文件src/Zend/zend_API.h : 577-583行,這個的作用其實是給一個string類型zval變量賦值
	const char *__s=(s);				\		
	zval *__z = (z);					\
	Z_STRLEN_P(__z) = strlen(__s);		\		//設置zval字符串長度
	Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\	//設置zval字符串的值
	Z_TYPE_P(__z) = IS_STRING;			\		//設置zval字符串的類型為字符串
} while (0)

因此,RETURN_STRING(formatinfo, 1)展開后為:

do {
	const char *__s=(formatinfo);
	zval *__z = (return_value);			//這里面的return_value估計是內核定義的,類似 zval *return_value;
	(*__z).value.str.len = strlrn(__s);		//等價於__z->value.str.len
	(*__z).value.str.val = (1?estrndup(__s, (*__z).value.str.len):(char*)__s);
	(*__z).type = 6;	
}
編譯測試
編譯的時候需要安裝好的php,比如我的php安裝在/usr/local/php/目錄下面

cd mytest;		//今日剛才編寫的函數擴展目錄
/usr/local/php/bin/phpize 	//運行phpize,生成configure文件
./configure --with-php-config=/usr/local/php/bin/php-config 	//configure,后面的--with-php-config會生成so文件到安裝好的擴展目錄,當然也可以不用加,聲稱之后手動copy過去
make	//有錯誤的話修正
make install 	//運行之后會提示類似下面的內容
#Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/
#修改配置文件php.ini添加extension = mytest.so
#測試
php -r 'var_dump(log_get_title());'

輸出下面內容的話,恭喜你成功了

[root@iforever logs]# php -r 'var_dump(get_log_title());' && date
string(39) "[2015-05-19 22:52:29 1432047149.755613]"
2015年 05月 19日 星期二 22:52:29 CST

5/19/2015 10:54:38 PM

本文版權歸作者iforever(luluyrt@163.com)所有,未經作者本人同意禁止任何形式的轉載,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM