PHP Extension 是什么呢?很多写PHP的工程师,或许不知道PHP Extension是怎么做出来的,其实PHP 的最底层是使用c 语言,每一句PHP 的语法,都是透过c 语言来实现,所以我们可以藉由c ,去加强PHP 的功能,让PHP 更方便使用,一个正常的PHP Extension制作时,要先编写config.m4 这个档案,虽然这个档案不难写,不过他与Makefile的格式落差很大,这里就介绍如何使用Makefile 来编译PHP Extension ,先介绍一下正常的PHP Extension编译流程,phpize会建立Makefile档案, ./configure 这个指令会自动检查相关package 是否安装
- 建立c code 与config.m4
- phpize (下Linux 指令phpize)
- ./configure
- make
- mv modules/xxx.so /extension : 将编译出来的so档,搬到extension目录下,这样就算完成一个PHP Extension
制作php extension Makefile
基实phpize的行为就是建立Makefile, libtool 等等工具,./configure就是检查一些设定是否正常,以及路径设定,即然我都要自已写php extension了,那就跳过这两个过程吧,自已写Makefile。
- 首先我们先使用phpize ,自动生出一个Makefile,然后再把他改成我们想要的格式。
- phpize & mv Makefile Makefile.global : 把Makefile改成Makefile.global
修改Makefile.global成我们要的样子Makefile.global范例
- 加入php 安装的目录PHP_DIR = /home/program/php (路径自已修改吧)
- 将部分变数的值改到PHP_DIR ,如prefix = $(PHP_DIR),phpincludedir = $(PHP_DIR)/include/php
- phplibdir = $(SRC_PATH)/modules :指定编译完成后,so档的路径
- PHP_PECL_EXTENSION = extension name //(注意名称不要重覆)
- srcdir , builddir , top_srcdir , top_builddir ,修改至当前目录,要用绝对目录
简化过后的Makefile
Makefile.global弄半天,最后终于简化完成,以后要编译php extension就方便多了,正式写一个要用来编译程式的Makefile ,你看! 下面的PHP Makefile 多么简短。
Example
SRC_PATH = $ ( shell pwd )
LDEF = - DCOMPILE_DL_MyExtension
CXXFILE = myClass . cc extension . cc
EXTRA_CXXFLAGS =
CXXOUTPUT = MyExtension
include Makefile . global
cp :
sudo cp ./ modules / $ ( CXXOUTPUT ). so / home / php_extension /
make 的结果
Example
create myClass . lo
create myClass . o
create extension . lo
create extension . o
create MyExtension . la
create MyExtension . so
//最后产生MyExtension.so 成功
接收php 传进来的变数的方式,使用zend_parse的function,有下列两种,其中[sal,lsl]代表要接放的变数型态。
- zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"sal",xxx,xx)
- zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,num_args TSRMLS_CC,"lsl", xx,xx,xx,xx)
- l : 代表long
- s : string
- a : array
- b : boolean
- d : double
- 回传result 给php的方式有下列几种
- RETURN_LONG : 回传long
- RETURN_STRING : 回传字串
- RETURN_DOUBLE : 回传倍精数
- RETURN_BOOL : 回传boolean (true or false)
建立一个php extension function
要写一个extension function ,就是使用PHP_FUNCTION 这个function ,而传进去的第一个参数,就是function 名称,写好之后,就可以在php 里使用simple("xxx");
Example
PHP_FUNCTION ( simple )
{
char * str = NULL ;
char * tmp = new char [ 50 ];
string result = "" ;
int str_len = 0 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS () TSRMLS_CC ,
"s" ,
& str ,& str_len ) == FAILURE ) {
RETURN_NULL ();
}
sprintf ( tmp , "Your input string is [%s]" , str );
result = tmp ;
delete [] tmp ;
RETURN_STRING ( const_cast < char *>( result . c_str ()), 1 );
}
第二个范例是function entry 中定义的add ,主要功能是将第一个参数与第二个参数做加总的功能,在php extension 中,所有的数字回偾都是使用RETURN_LONG,不需要依int ,long,float 去判断回传值,这是由于php 变数型态很自由,不用区分得这么细。
Example
PHP_FUNCTION ( add )
{
int num_args = ZEND_NUM_ARGS ();
if ( num_args != 2 ) {
RETURN_LONG ( 0 );
}
int result = 0 , int1 , int2 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS () TSRMLS_CC ,
"ll" ,
& int1 ,& int2 ) == FAILURE ) {
RETURN_NULL ();
}
result = int1 + int2 ;
RETURN_LONG ( result );
}
相关问题
warning: deprecated conversion from string constant to 'char*'
我升级gcc 4.2.0 后,编译就会出现这个Warning,使用gcc 3.4.6 就没事了。
第二招,碰到Warning不要停掉,在Makefile档案中,将-Werror 这个属性拿掉吧
undefined symbol:__gxx_personality_v0
因为你使用c++ 语法,但是却没有载入c++ 的library
解法:将Makefile 的CC 加上-lstdc++ ,加上这句后,编译时,会自动载入/usr/lib/libstdc++.so。
Example
CC = cc - lstdc ++
错误: Invalid library (maybe not a PHP library)的处理
这代表,php在载入so档时,找不到程序入口,c & c++的程序入口是main ,而php extension的程序入口是zend_module_entry ,但是因为我有使用到c++ 语法,c++有个特性,在编译时,会自动乱改变数及function名称。
Example
zend_module_entry MyExtension_module_entry
像这句语法,经过c++ 编译后,就可能变成MyExtension_module_entryii,结果造成找不到程序入口而报错。
解法就是多加一句extern "C"
Example
zend_module_entry MyExtension_module_entry = {
}
extern "C" {
ZEND_GET_MODULE ( MyExtension )
}
为何要加extern "C" 呢?
我们知道C++ 有overloading 的功能,一个function 可以有多种不同的参数数量,可是c++ 是怎么办到的呢,其实他在编译程式的时候,就会自动做function name 的mapping ,例如下面的例子,可是单纯的c 语言并不懂这个东西,所以当c 语言要去读取c++ 的function 时,就必需加上extern "C" ,强迫c++ 不要乱改名称,这样c语言才能正确的执行function 。
Example
int test ( int a ){}
int test ( char b , char c ){}
//编译后
test ( int a ) => test_1 ( int a )
test ( char b , char c ) => test_2 ( char b , char c )