淺談PHP Extension的開發(fā)——基礎篇
下面是“say_hello.c”中需要編寫的info_func的具體代碼:
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(say_hello)
{
php_info_print_table_start();
php_info_print_table_header(2, "say_hello support", "enabled");
php_info_print_table_row(2, "author", "Zhang Yang"); /* Replace with your name */
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
可以看到我們編寫了兩行內容、組件是否可用以及作者信息。
編寫核心函數(shù)
編寫核心函數(shù),總共分為三步:1、使用宏PHP_FUNCTION定義函數(shù)體;2、使用宏ZEND_BEGIN_ARG_INFO和ZEND_END_ARG_INFO定義參數(shù)信息;3、使用宏PHP_FE將函數(shù)加入到say_hello_functions中。下面分步說明。
使用宏PHP_FUNCTION定義函數(shù)體
PHP_FUNCTION(say_hello_func)
{
char *name;
int name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE)
{
return;
}
php_printf("Hello %s!", name);
RETURN_TRUE;
}
上文說過,編寫PHP擴展時幾乎所有東西都不能裸寫,而是必須使用相應的宏。從上面代碼可以清楚看到這一點。總體來說,核心函數(shù)代碼一般由如下幾部分構成:
定義函數(shù),這一步通過宏PHP_FUNCTION實現(xiàn),函數(shù)的外部名稱就是宏后面括號里面的名稱。
聲明并定義局部變量。
解析參數(shù),這一步通過zend_parse_parameters函數(shù)實現(xiàn),這個函數(shù)的作用是從函數(shù)用戶的輸入棧中讀取數(shù)據,然后轉換成相應的函數(shù)參數(shù)填入變量以供后面核心功能代碼使用。zend_parse_parameters的第一個參數(shù)是用戶傳入參數(shù)的個數(shù),可以由宏“ZEND_NUM_ARGS() TSRMLS_CC”生成;第二個參數(shù)是一個字符串,其中每個字母代表一個變量類型,我們只有一個字符串型變量,所以第二個參數(shù)是“s”;最后各個參數(shù)需要一些必要的局部變量指針用于存儲數(shù)據,下表給出了不同變量類型的字母代表及其所需要的局部變量指針。
參數(shù)解析完成后就是核心功能代碼,我們這里只是輸出一行字符,php_printf是Zend版本的printf。
最后的返回值也是通過宏實現(xiàn)的。RETURN_TRUE宏是返回布爾值“true”。
使用宏ZEND_BEGIN_ARG_INFO和ZEND_END_ARG_INFO定義參數(shù)信息
參數(shù)信息是函數(shù)所必要部分,這里不做深究,直接給出相應代碼:
ZEND_BEGIN_ARG_INFO(arginfo_say_hello_func, 0)
ZEND_END_ARG_INFO()
如需了解具體信息請閱讀相關宏定義。
使用宏PHP_FE將函數(shù)加入到say_hello_functions中
最后,我們需要將剛才定義的函數(shù)和參數(shù)信息加入到say_hello_functions數(shù)組里,代碼如下:
const zend_function_entry say_hello_functions[] = {
PHP_FE(say_hello_func, arginfo_say_hello_func)
{NULL, NULL, NULL}
};
這一步就是通過PHP_EF宏實現(xiàn),注意這個數(shù)組最后一行必須是{NULL, NULL, NULL} ,請不要刪除。
下面是編寫完成后的say_hello.c全部代碼:
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: |
+----------------------------------------------------------------------+
*/
/* $Id: header 297205 2010-03-30 21:09:07Z johannes $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_say_hello.h"
/* If you declare any globals in php_say_hello.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(say_hello)
*/
/* True global resources - no need for thread safety here */
static int le_say_hello;
/* {{{ PHP_FUNCTION
*/
PHP_FUNCTION(say_hello_func)
{
char *name;
int name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE)
{
return;
}
php_printf("Hello %s!", name);
RETURN_TRUE;
}
ZEND_BEGIN_ARG_INFO(arginfo_say_hello_func, 0)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ say_hello_functions[]
*
* Every user visible function must have an entry in say_hello_functions[].
*/
const zend_function_entry say_hello_functions[] = {
PHP_FE(say_hello_func, arginfo_say_hello_func)
{NULL, NULL, NULL} /* Must be the last line in say_hello_functions[] */
};
/* }}} */
/* {{{ say_hello_module_entry
*/
zend_module_entry say_hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"say_hello",
say_hello_functions,
NULL,
NULL,
NULL,
NULL,
PHP_MINFO(say_hello),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_SAY_HELLO
ZEND_GET_MODULE(say_hello)
#endif
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(say_hello)
{
php_info_print_table_start();
php_info_print_table_header(2, "say_hello support", "enabled");
php_info_print_table_row(2, "author", "Zhang Yang"); /* Replace with your name */
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
編譯并安裝擴展
在say_hello目錄下輸入下面命令:
/usr/bin/phpize
./configure
make
make install
這樣就完成了say_hello擴展的安裝(如果沒有報錯的話)。
這時如果你去放置php擴展的目錄下,會發(fā)現(xiàn)多了一個say_hello.so的文件。如下圖所示:
下面就是將其加入到php.ini配置中,然后重啟Apache(如果需要的話)。這些都是PHP基本配置的內容,我就不詳述了。
擴展測試
如果上面順利完成,這時運行phpinfo(),應該能看到如下信息:
這說明擴展已經安裝成功了。然后我們編寫一個測試用PHP腳本:
<?php
say_hello_func('Zhang Yang');
?>
執(zhí)行這個腳本,結果如下:
說明擴展已經正常工作了。
總結
這篇文章主要用示例方法介紹PHP Extension的開發(fā)基礎。在PHP的使用中,也許是因為需要支持新的組件(如新的數(shù)據庫),又或是業(yè)務需要或性能需要,幾乎都會遇到需要開發(fā)PHP擴展的地方。后續(xù)如果有機會,我會寫文章介紹一些關于擴展開發(fā)較為深入的東西,如擴展模塊生命周期、INI使用以及編寫面向對象的擴展模塊等等。
本文基于署名-非商業(yè)性使用 3.0許可協(xié)議發(fā)布,歡迎轉載或演繹,但是必須保留本文的署名張洋(包含鏈接),且不得用于商業(yè)用途。如您有任何疑問或者授權方面的協(xié)商,請與我聯(lián)系。
相關文章
PHP 雜談《重構-改善既有代碼的設計》之一 重新組織你的函數(shù)
我把我比較喜歡的和比較關注的地方寫下來和大家分享。上次我寫了篇《php 跟老大的對話》。還是有很多疑問,這書幫了我不少的忙2012-04-04