精品人妻无码一区二区三区软件 ,麻豆亚洲AV成人无码久久精品,成人欧美一区二区三区视频,免费av毛片不卡无码

您現(xiàn)在的位置是:首頁(yè)計(jì)算機(jī)應(yīng)用論文

php 新增函數(shù)

發(fā)布時(shí)間: 1

該章節(jié)中的內(nèi)容可能已經(jīng)比較過(guò)時(shí)了,它講解了如何擴(kuò)展 PHP3。如果您對(duì) PHP 4 感興趣,請(qǐng)閱讀“Zend API”的有關(guān)章節(jié)。同時(shí),您還可以閱讀 PHP 源文檔中的一些文檔,例如 README.SELF-CONTAINED-EXTENSIONSREADME.EXT_SKEL。

為 PHP 新增函數(shù)

函數(shù)原型

所有的函數(shù)有著如下形式:

void php3_foo(INTERNAL_FUNCTION_PARAMETERS) {
     
}
即使您的函數(shù)沒(méi)有任何參數(shù),這也是它被調(diào)用的方式。

函數(shù)參數(shù)

參數(shù)總是屬于 pval 類型。該類型包含了各個(gè)參數(shù)的實(shí)際類型。因此,如果您的函數(shù)有兩個(gè)參數(shù),您應(yīng)該在您的函數(shù)頂部做如下工作:

例子 E-1. 取得函數(shù)參數(shù)

pval *arg1, *arg2;
if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&arg1,&arg2)==FAILURE) {
   WRONG_PARAM_COUNT;
}
注意:參數(shù)既可以被值(value)傳遞又可以被引用(reference)傳遞。兩種情況您都需要將 &(pval *) 傳遞給 getParameters 函數(shù)。如果您想檢查第 n 個(gè)參數(shù)是否通過(guò)引用傳遞給您,您可以使用 ParameterPassedByReference(ht,n) 函數(shù)。它的返回值為 0 或者 1。

當(dāng)您改變了任何已傳遞的參數(shù),無(wú)論它們是以值或者引用的方式傳遞,您都可以對(duì)它使用 pval_destructor 函數(shù)來(lái)銷毀它;蛘呷绻且粋(gè)您想添加的數(shù)組,您可以使用類似于 internal_functions.h 中定義函數(shù)的方法來(lái)將返回值 return_value 作為數(shù)組來(lái)操作。

此外當(dāng)你將一個(gè)參數(shù)改為 IS_STRING 時(shí)要確保先給 estrdup() 出來(lái)的字符串賦值以及給出字符串長(zhǎng)度,然后才將它的類型改為 IS_STRING。如果要修改一個(gè)已經(jīng)是 IS_STRING 或 IS_ARRAY 的參數(shù)應(yīng)該先對(duì)其運(yùn)行 pval_destructor。

可變函數(shù)參數(shù)

函數(shù)可以接受不同數(shù)目的參數(shù)。如果你的函數(shù)可以接受 2 或 3 個(gè)參數(shù),這樣用:

例子 E-2. 可變函數(shù)參數(shù)

pval *arg1, *arg2, *arg3;
int arg_count = ARG_COUNT(ht);

if (arg_count < 2 || arg_count > 3 ||
    getParameters(ht,arg_count,&arg1,&arg2,&arg3)==FAILURE) {
    WRONG_PARAM_COUNT;
}

使用函數(shù)參數(shù)

每個(gè)參數(shù)的類型存放在 pval 的類型字段中。可以是以下任何一種:

表格 E-1. PHP 內(nèi)部類型

IS_STRING字符串
IS_DOUBLE雙精度浮點(diǎn)型
IS_LONG長(zhǎng)整型
IS_ARRAY數(shù)組
IS_EMPTYNone
IS_USER_FUNCTION??
IS_INTERNAL_FUNCTION??(如果其中某些不能被傳遞給一個(gè)函數(shù),則刪除)
IS_CLASS??
IS_OBJECT??

如果得到了一種類型的參數(shù)但是卻想按照另一種類型來(lái)使用,或者想強(qiáng)制參數(shù)為某種類型,可以使用以下的轉(zhuǎn)換函數(shù):

convert_to_long(arg1);
convert_to_double(arg1);
convert_to_string(arg1); 
convert_to_boolean_long(arg1); /* If the string is "" or "0" it becomes 0, 1 otherwise */
convert_string_to_number(arg1);  /* Converts string to either LONG or DOUBLE depending on string */

這些函數(shù)都是即時(shí)轉(zhuǎn)換的,并不返回任何值。

實(shí)際上的參數(shù)被存放在一個(gè)聯(lián)合中,成員為:

  • IS_STRING: arg1->value.str.val

  • IS_LONG: arg1->value.lval

  • IS_DOUBLE: arg1->value.dval

函數(shù)中的內(nèi)存管理

函數(shù)所使用的任何內(nèi)存都應(yīng)該通過(guò) emalloc() 或者 estrdup() 來(lái)申請(qǐng)。它們是內(nèi)存處理抽象函數(shù),看上去就像普通的 malloc() 和 strdup() 函數(shù)一樣。內(nèi)存應(yīng)該用 efree() 來(lái)釋放。

程序中有兩種內(nèi)存:作為變量被返回到解釋器中的內(nèi)存,以及內(nèi)部函數(shù)所需要的臨時(shí)存儲(chǔ)空間。當(dāng)把一個(gè)字符串賦給一個(gè)返回解釋器的變量時(shí)需要確保首先通過(guò) emalloc() 或者 estrdup() 分配了內(nèi)存。該內(nèi)存決不該由你來(lái)釋放,除非你在同一個(gè)函數(shù)中后來(lái)又覆蓋了原來(lái)的賦值(這并不是一種好的編程實(shí)踐)。

任何在你的函數(shù)/庫(kù)中所需要的臨時(shí)/永久內(nèi)存都要通過(guò)這三個(gè)函數(shù)來(lái)進(jìn)行:emalloc(),estrdup() 和 efree()。它們的行為完全和它們相對(duì)應(yīng)的函數(shù)相同。任何通過(guò) emalloc() 或 estrdup() 都要用 efree() 在某個(gè)環(huán)節(jié)釋放,除非它們本來(lái)就需要存在到程序結(jié)束。否則就會(huì)出現(xiàn)內(nèi)存泄漏!八鼈兊男袨橥耆退鼈兿鄬(duì)應(yīng)的函數(shù)相同”的意思是:如果你用 efree() 釋放了不是由 emalloc() 或 estrdup() 分配的內(nèi)存時(shí)可能會(huì)導(dǎo)致段錯(cuò)誤。所以要留意釋放所有不需要的內(nèi)存。

如果編譯時(shí)指定了 "-DDEBUG",PHP 將在腳本運(yùn)行結(jié)束后顯示出所有通過(guò) emalloc() 和 estrdup() 分配但是沒(méi)有用 efree() 釋放的內(nèi)存列表。

在符號(hào)表中設(shè)定變量

有一些宏可以使在符號(hào)表中設(shè)定變量更容易:

  • SET_VAR_STRING(name,value)

  • SET_VAR_DOUBLE(name,value)

  • SET_VAR_LONG(name,value)

警告

要注意 SET_VAR_STRING。值的部分必須是人工分配出來(lái)的,因?yàn)閮?nèi)存管理代碼會(huì)在以后嘗試釋放該指針。不要將靜態(tài)分配的內(nèi)存?zhèn)鬟f給 SET_VAR_STRING。

PHP 中的符號(hào)表是以散列表來(lái)實(shí)現(xiàn)的。任何時(shí)候 &symbol_table 都是一個(gè)指向 'main' 符號(hào)表的指針,active_symbol_table points 指向當(dāng)前活動(dòng)的符號(hào)表(二者在開(kāi)始時(shí)等同,而在函數(shù)內(nèi)不同)。

以下例子使用了 'active_symbol_table'。如果你指明要工作于 'main' 符號(hào)表,應(yīng)該用 &symbol_table 來(lái)替代。此外,同樣的函數(shù)也能像下面說(shuō)明的作用于數(shù)組。

例子 E-3. 檢查 $foo 是否存在于符號(hào)表

if (hash_exists(active_symbol_table,"foo",sizeof("foo"))) { exists... }
else { doesn't exist }

例子 E-4. 在符號(hào)表中找到一個(gè)變量的字長(zhǎng)

hash_find(active_symbol_table,"foo",sizeof("foo"),&pvalue);
check(pvalue.type);
PHP 中的數(shù)組使用了和符號(hào)表同一個(gè)散列表來(lái)實(shí)現(xiàn)。這意味著以上兩個(gè)函數(shù)也可以用來(lái)檢查數(shù)組中的變量。

如果要在符號(hào)表中定義一個(gè)新數(shù)組,應(yīng)該這樣做。

首先,要用 hash_exists() 或 hash_find() 檢查它是否存在并且正確中止。

接著,初始化數(shù)組:

例子 E-5. 初始化新數(shù)組

pval arr;
  
if (array_init(&arr) == FAILURE) { failed... };
hash_update(active_symbol_table,"foo",sizeof("foo"),&arr,sizeof(pval),NULL);
這段代碼在活動(dòng)符號(hào)表中定義了一個(gè)名為 $foo 的新數(shù)組。這是個(gè)空數(shù)組。

這里展示了怎樣向其中加入新的條目:

例子 E-6. 向數(shù)組中加入新的條目

pval entry;
  
entry.type = IS_LONG;
entry.value.lval = 5;
  
/* defines $foo["bar"] = 5 */
hash_update(arr.value.ht,"bar",sizeof("bar"),&entry,sizeof(pval),NULL); 

/* defines $foo[7] = 5 */
hash_index_update(arr.value.ht,7,&entry,sizeof(pval),NULL); 

/* defines the next free place in $foo[],
 * $foo[8], to be 5 (works like php2)
 */
hash_next_index_insert(arr.value.ht,&entry,sizeof(pval),NULL);
如果要修改一個(gè)插入到散列表中的值,必須先將其提取出來(lái)。要避免額外開(kāi)銷你可以給 hash add 函數(shù)提供一個(gè) pval ** 參數(shù),它將被表中相應(yīng)單元的 pval * 地址所更新。如果其值為 NULL(如同以上所有的例子),該參數(shù)被忽略。

hash_next_index_insert() 或多或少使用了如同 PHP 2.0 中 "$foo[] = bar;" 的邏輯。

如果要建立一個(gè)從函數(shù)返回的數(shù)組,可以就像以上那樣初始化數(shù)組:

if (array_init(return_value) == FAILURE) { failed...; }

接著用有用的函數(shù)加入值:

add_next_index_long(return_value,long_value);
add_next_index_double(return_value,double_value);
add_next_index_string(return_value,estrdup(string_value));

當(dāng)然了,如果如果在數(shù)組初始化后添加不正確,你應(yīng)該先查看一下數(shù)組:

pval *arr;
  
if (hash_find(active_symbol_table,"foo",sizeof("foo"),(void **)&arr)==FAILURE) { can't find... }
else { use arr->value.ht... }

注意 hash_find 接受一個(gè)指向 pval 指針的指針,并不是 pval 指針。

以上任何 hash 函數(shù)返回 SUCCESS 或 FAILURE(除了 hash_exists(),它返回一個(gè)布爾真值)。

Returning simple values

A number of macros are available to make returning values from a function easier.

The RETURN_* macros all set the return value and return from the function:

  • RETURN

  • RETURN_FALSE

  • RETURN_TRUE

  • RETURN_LONG(l)

  • RETURN_STRING(s,dup) If dup is TRUE, duplicates the string

  • RETURN_STRINGL(s,l,dup) Return string (s) specifying length (l).

  • RETURN_DOUBLE(d)

The RETVAL_* macros set the return value, but do not return.

  • RETVAL_FALSE

  • RETVAL_TRUE

  • RETVAL_LONG(l)

  • RETVAL_STRING(s,dup) If dup is TRUE, duplicates the string

  • RETVAL_STRINGL(s,l,dup) Return string (s) specifying length (l).

  • RETVAL_DOUBLE(d)

The string macros above will all estrdup() the passed 's' argument, so you can safely free the argument after calling the macro, or alternatively use statically allocated memory.

If your function returns boolean success/error responses, always use RETURN_TRUE and RETURN_FALSE respectively.

Returning complex values

Your function can also return a complex data type such as an object or an array.

Returning an object:

  1. Call object_init(return_value).

  2. Fill it up with values. The functions available for this purpose are listed below.

  3. Possibly, register functions for this object. In order to obtain values from the object, the function would have to fetch "this" from the active_symbol_table. Its type should be IS_OBJECT, and it's basically a regular hash table (i.e., you can use regular hash functions on .value.ht). The actual registration of the function can be done using:

    add_method( return_value, function_name, function_ptr );

The functions used to populate an object are:

  • add_property_long( return_value, property_name, l ) - Add a property named 'property_name', of type long, equal to 'l'

  • add_property_double( return_value, property_name, d ) - Same, only adds a double

  • add_property_string( return_value, property_name, str ) - Same, only adds a string

  • add_property_stringl( return_value, property_name, str, l ) - Same, only adds a string of length 'l'

Returning an array:

  1. Call array_init(return_value).

  2. Fill it up with values. The functions available for this purpose are listed below.

The functions used to populate an array are:

  • add_assoc_long(return_value,key,l) - add associative entry with key 'key' and long value 'l'

  • add_assoc_double(return_value,key,d)

  • add_assoc_string(return_value,key,str,duplicate)

  • add_assoc_stringl(return_value,key,str,length,duplicate) specify the string length

  • add_index_long(return_value,index,l) - add entry in index 'index' with long value 'l'

  • add_index_double(return_value,index,d)

  • add_index_string(return_value,index,str)

  • add_index_stringl(return_value,index,str,length) - specify the string length

  • add_next_index_long(return_value,l) - add an array entry in the next free offset with long value 'l'

  • add_next_index_double(return_value,d)

  • add_next_index_string(return_value,str)

  • add_next_index_stringl(return_value,str,length) - specify the string length

Using the resource list

PHP has a standard way of dealing with various types of resources. This replaces all of the local linked lists in PHP 2.0.

Available functions:

  • php3_list_insert(ptr, type) - returns the 'id' of the newly inserted resource

  • php3_list_delete(id) - delete the resource with the specified id

  • php3_list_find(id,*type) - returns the pointer of the resource with the specified id, updates 'type' to the resource's type

Typically, these functions are used for SQL drivers but they can be used for anything else; for instance, maintaining file descriptors.

Typical list code would look like this:

例子 E-7. Adding a new resource

RESOURCE *resource;

/* ...allocate memory for resource and acquire resource... */
/* add a new resource to the list */
return_value->value.lval = php3_list_insert((void *) resource, LE_RESOURCE_TYPE);
return_value->type = IS_LONG;

例子 E-8. Using an existing resource

pval *resource_id;
RESOURCE *resource;
int type;

convert_to_long(resource_id);
resource = php3_list_find(resource_id->value.lval, &type);
if (type != LE_RESOURCE_TYPE) {
	php3_error(E_WARNING,"resource index %d has the wrong type",resource_id->value.lval);
	RETURN_FALSE;
}
/* ...use resource... */

例子 E-9. Deleting an existing resource

pval *resource_id;
RESOURCE *resource;
int type;

convert_to_long(resource_id);
php3_list_delete(resource_id->value.lval);
The resource types should be registered in php3_list.h, in enum list_entry_type. In addition, one should add shutdown code for any new resource type defined, in list.c's list_entry_destructor() (even if you don't have anything to do on shutdown, you must add an empty case).

Using the persistent resource table

PHP has a standard way of storing persistent resources (i.e., resources that are kept in between hits). The first module to use this feature was the MySQL module, and mSQL followed it, so one can get the general impression of how a persistent resource should be used by reading mysql.c. The functions you should look at are:

php3_mysql_do_connect
php3_mysql_connect()
php3_mysql_pconnect()

The general idea of persistence modules is this:

  1. Code all of your module to work with the regular resource list mentioned in section (9).

  2. Code extra connect functions that check if the resource already exists in the persistent resource list. If it does, register it as in the regular resource list as a pointer to the persistent resource list (because of 1., the rest of the code should work immediately). If it doesn't, then create it, add it to the persistent resource list AND add a pointer to it from the regular resource list, so all of the code would work since it's in the regular resource list, but on the next connect, the resource would be found in the persistent resource list and be used without having to recreate it. You should register these resources with a different type (e.g. LE_MYSQL_LINK for non-persistent link and LE_MYSQL_PLINK for a persistent link).

If you read mysql.c, you'll notice that except for the more complex connect function, nothing in the rest of the module has to be changed.

The very same interface exists for the regular resource list and the persistent resource list, only 'list' is replaced with 'plist':

  • php3_plist_insert(ptr, type) - returns the 'id' of the newly inserted resource

  • php3_plist_delete(id) - delete the resource with the specified id

  • php3_plist_find(id,*type) - returns the pointer of the resource with the specified id, updates 'type' to the resource's type

However, it's more than likely that these functions would prove to be useless for you when trying to implement a persistent module. Typically, one would want to use the fact that the persistent resource list is really a hash table. For instance, in the MySQL/mSQL modules, when there's a pconnect() call (persistent connect), the function builds a string out of the host/user/passwd that were passed to the function, and hashes the SQL link with this string as a key. The next time someone calls a pconnect() with the same host/user/passwd, the same key would be generated, and the function would find the SQL link in the persistent list.

Until further documented, you should look at mysql.c or msql.c to see how one should use the plist's hash table abilities.

One important thing to note: resources going into the persistent resource list must *NOT* be allocated with PHP's memory manager, i.e., they should NOT be created with emalloc(), estrdup(), etc. Rather, one should use the regular malloc(), strdup(), etc. The reason for this is simple - at the end of the request (end of the hit), every memory chunk that was allocated using PHP's memory manager is deleted. Since the persistent list isn't supposed to be erased at the end of a request, one mustn't use PHP's memory manager for allocating resources that go to it.

When you register a resource that's going to be in the persistent list, you should add destructors to it both in the non-persistent list and in the persistent list. The destructor in the non-persistent list destructor shouldn't do anything. The one in the persistent list destructor should properly free any resources obtained by that type (e.g. memory, SQL links, etc). Just like with the non-persistent resources, you *MUST* add destructors for every resource, even it requires no destruction and the destructor would be empty. Remember, since emalloc() and friends aren't to be used in conjunction with the persistent list, you mustn't use efree() here either.

Adding runtime configuration directives

Many of the features of PHP can be configured at runtime. These configuration directives can appear in either the designated php3.ini file, or in the case of the Apache module version in the Apache .conf files. The advantage of having them in the Apache .conf files is that they can be configured on a per-directory basis. This means that one directory may have a certain safemodeexecdir for example, while another directory may have another. This configuration granularity is especially handy when a server supports multiple virtual hosts.

The steps required to add a new directive:

  1. Add directive to php3_ini_structure struct in mod_php3.h.

  2. In main.c, edit the php3_module_startup function and add the appropriate cfg_get_string() or cfg_get_long() call.

  3. Add the directive, restrictions and a comment to the php3_commands structure in mod_php3.c. Note the restrictions part. RSRC_CONF are directives that can only be present in the actual Apache .conf files. Any OR_OPTIONS directives can be present anywhere, include normal .htaccess files.

  4. In either php3take1handler() or php3flaghandler() add the appropriate entry for your directive.

  5. In the configuration section of the _php3_info() function in functions/info.c you need to add your new directive.

  6. And last, you of course have to use your new directive somewhere. It will be addressable as php3_ini.directive.



轉(zhuǎn)載請(qǐng)注明來(lái)自:http://www.jinnzone.com/jisuanjiyingyonglw/153.html