首頁 後端開發 php教程 編寫PHP擴充函數的參數

編寫PHP擴充函數的參數

Dec 07, 2016 pm 03:27 PM
php

函數的參數 
最簡單的取得函數呼叫者傳遞過來的參數就是使用zend_parse_parameters()函數。 zend_parse_parameters()函數的前幾個參數我們直接用核心裡巨集來產生便可以了,形式為:ZEND_NUM_ARGS() TSRMLS_CC,注意兩者之間有個空格,但是沒有逗號。從名字可以看出,ZEND_NUM_ARGS()代表參數的個數。 緊接著需要傳遞給zend_parse_parameters()函數的參數是一個用於格式化的字串,就像printf的第一個參數一樣。下面表示了最常用的幾個符號。
type_spec是格式化字串,其常見的意義如下: 
參數   代表的類型 
b   Boolean 
l   Integer 整數 
d    Array 數組 
o對象. 
這個函數就像printf()函數一樣,後面的參數是與格式化字串裡的格式一一對應的。有些基礎類型的資料會直接對應成C語言裡的型別。
ZEND_FUNCTION(sample_getlong) { 

    long foo; 
    if (zend_parse_parameters(ZEND_NUM_ARGS==() TSRMLS_CC,"l", )     RETURN_NULL(); 
    } 
    php_printf("The integer value of the parameter is: %ldn", foo); 
    RETURN_TRUE; 

一般來說,int和long這兩種資料型態的資料往往是相同的,但也有例外。所以我們不應該改把long的陣列放在一個int裡,尤其是在64位元平台裡,那將引發一些不容易排除的Bug。所以透過zend_parse_parameter()函數接收參數時,我們應該使用核心約定好的那些類型的變數作為載體。
參數  對應C裡的資料型別 
b   zend_bool 
l   long 
d   double 
s   char*, int 前1val zval* 
O   zval*, zend_class_entry*
z   zval* 
Z   zval** 
注意,所有的PHP語言中的複合型別參數都需要zval*型別來作為載體,因為它們都是核心自訂的一些資料結構。我們一定要確認參數和載體的型​​別一致,如果需要,它可以進行型別轉換,例如把array轉換成stdClass物件。 s和O(字母大寫歐)類型需要單獨說一些,因為它們都需要兩個載體。我們將在接下來的章節中了解php中物件的具體實作。這樣我們改寫一下我們在第五章定義的一個函數: 
function sample_hello_world($name) { 
    echo "Hello $name!n"; 

在編寫擴充功能時,我們需要用擴充功能(Tparend)來接收這個字串: 
ZEND_FUNCTION(sample_hello_world) { 
    char *name; 
    int name_len; 

鱧== FAILURE) 
    { 
        RETURN_NULL() ; 
    } 
    php_printf("Hello "); 
    PHPWRITE(name, name_len); 
   ,它便會執行失敗,並回傳FAILURE。
如果我們需要接收多個參數,可以直接在zend_parse_paramenters()的參數裡羅列接收載體便可以了,如: 
function sample_hello_world($name, $greeting) { 
  !n"; 

sample_hello_world('John Smith', 'Mr.'); 
在PHP擴充裡應該這樣來實現: 
ZEND_FUNCTION(sample_hello_world) {   char *greeting;
    int greeting_len; 
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&name, &name_len, &greeting, &greeting_len) == FAILURE) { 
   Hello "); 
    PHPWRITE(greeting, greeting_len); 
php_printf(" "); 
    PHPWRITE(name, name_len); 
    php_printf("!n"); 

除了上面定義的參數,還有其它的三個參數來增強我們接收參數的能力如下: Type Modifier   Meaning 
|       它之前的參數都是必須的,之後的都是非必須的,也就是預設值的。 
!       如果接收了一個PHP語言裡的null變量,直接將其轉換為C語言裡的NULL,而不是封裝成IS_NULL類型的zval。
/       如果傳遞過來的變數與別的變數共用一個zval,而且不是引用,則進行強制分離,新的zval的is_ref__gc==0, and refcount__gc==1. 
函數參數的預設值 
現在讓我們繼續改寫sample_hello_world(), 接下來我們使用一些參數的預設值,在php語言裡就像下面這樣: 
function sample_hello_world($name, $greeting='Mr./Ms.') { 
 
 Hello $greeting $name!n"; 

sample_hello_world('Ginger Rogers','Ms.'); 
sample_hello_world('Fred Astaire'); 
此時即可以只傳送一個參數,也可以傳送到sample_hello_world('Fred Astaire');完整的兩個參數。 那同樣的功能我們怎麼在擴充函數裡實現呢?我們需要藉助zend_parse_parameters中的(|)參數,這個參數之前的參數被認為是必須的,之後的便認為是非必須的了,如果沒有傳遞,則不會去修改載體。
ZEND_FUNCTION(sample_hello_world) { 
    char *name; 
    int name_len; 
    char *greeting = "Mr./Mrs."; 1; 


    if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", 
      &name, &name_len, &greeting, &greeting_len) ==
    php_printf("Hello "); 
    PHPWRITE(greeting, greeting_len);
    php_printf(" "); 
      php_printf(" "); 
    PHPWRITE(name, name_len); 
    php_printf("!n"); 
}所以,我們需要自己來預先設定有載體的值,它往往是NULL,或是與函數邏輯有關的值。 每個zval,包括IS_NULL型的zval,都需要佔用一定的記憶體空間,並且需要cpu的計算資源來為它申請記憶體、初始化,並在它們完成工作後釋放掉。但是很多程式碼都沒有意識到這一點。有許多程式碼都會把一個null型的值包成zval的IS_NULL類型,在擴充開發裡這種操作是可以最佳化的,我們可以把參數接收城C語言裡的NULL。我們就這個問題看以下程式碼: 
ZEND_FUNCTION(sample_arg_fullnull) { 
    zval *val; 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRM_CC) "    RETURN_NULL(); 
    } 
    if (Z_TYPE_P(val) == IS_NULL) { 
        val = php_sample_make_defaultval(TSRMLS_C); 
       zval *val; 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z! ", 
                                 
    } 
    if (!val) { 
        val = php_sample_make_defaultval(TSRMLS_C));這兩段程式碼乍看之下並沒有什麼很大的不同,但是第一段程式碼確實需要更多的cpu和記憶體資源。可能這個技巧在平常沒有多大用,不過技多不壓身,知道總比不知道好。 

Forced Separation 
當一個變數傳遞給函數時候,無論它是否被引用,它的refcoung__gc屬性都會加一,至少成為2。一份是它自己,另一份是傳遞給函數的copy。在改變這個zval之前,有時會需要事先把它分成實際意義上的兩份copy。這就是"/"格式符的作用。它將把寫時複製的zval提前分成兩個完整獨立的copy,從而使我們可以在下面的程式碼中隨意的對其進行操作。否則我們可能需要不停的提醒自己對接收的參數進行分離等操作。 Like the NULL flag, this modifier goes after the type it means to impact. Also like the NULL flag, you won't know you need this feature until you actually have a use for it. 
5你的擴充能夠相容於舊版的PHP,或者你只想以zval為載體來接收參數,便可以考慮使用zend_get_parameters()函數來接收參數。 zend_get_parameters()與zend_parse_parameters()不同,從名字上我們便可以看出,它直接獲取,而不做解析。首先,它不會自動進行類型轉換,所有的參數在擴充實作中的載體都需要是zval類型的,下面讓我們來看一個最簡單的例子: 
ZEND_FUNCTION(sample_onearg) { 
    zval *firstarg; 
 (zend_get_parameters(ZEND_NUM_ARGS(), 1, &firstarg)== FAILURE) { 
        php_error_docref(NULL TSRMLS_遠NULL(); 
    } 
    /* Do something with firstarg.. . */ 

其次,zend_get_parameters()在接收失敗的時候,並不會自己拋出錯誤,它也不能方便的處理具有預設值的參數。 最後一點與zend_parse_parameters不同的是,它會自動的把所有符合copy-on-write的zval進行強制分離,產生一個嶄新的copy送到函數內部。如果你希望用它其它的特性,而唯獨不需要這個功能,可以去嘗試一下用zend_get_parameters_ex()函數來接收參數。 為了不對copy-on-write的變數進行分離操作,zend_get_parameters_ex()的參數是zval**類型的,而不是zval*。 這個函數不太常用,可能只會在你碰到一些極端問題時候才會想到它,而它用起來卻很簡單: 
ZEND_FUNCTION(sample_onearg) { 
    zval **firstarg; 
 &firstarg) == FAILURE) { 
        WRONG_PARAM_COUNT; 
    } 
    /* Do something with firstarg... 
    /* Do something with firstarg...因為它是在是在後期加入的,那個參數已經不再需要了。 
上面範例中也使用了WRONG_PARAM_COUNT巨集,它的功能是拋出一個E_WARNING等級的錯誤訊息,並自動return。 

可變參數 
有兩種其它的zend_get_parameter_**函數,專門用來解決參數很多或無法事先知道參數數目的問題。想想看php語言中var_dump()函數的用法,我們可以傳遞任意數量的參數,它在內核中的實作其實是這樣的: 
ZEND_FUNCTION(var_dump) { 
    int i, argc = ZEND_NUM_ARGS(); 🎟 zval ***args; 

    args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); 
    if (ZEND_NUM_ARGS() ==== 0 ) { 
        efree(args); 
        WRONG_PARAM_COUNT; 
   _var_dump(args[i], 1 TSRMLS_CC); 
    } 
    efree(args); 

程式首先取得參數數量,然後透過safe_emalloc函數申請了對應大小的記憶體來存放這些zval**類型的參數。這裡使用了zend_get_parameters_array_ex()函數來把傳遞給函數的參數填入args。你可能已經立即想到,還存在一個名為zend_get_parameters_array()的函數,唯一不同的是它將zval*類型的參數填入args中,並且需要ZEND_NUM_ARGS()作為參數。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1421
52
Laravel 教程
1315
25
PHP教程
1266
29
C# 教程
1239
24
在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

說明匹配表達式(PHP 8)及其與開關的不同。 說明匹配表達式(PHP 8)及其與開關的不同。 Apr 06, 2025 am 12:03 AM

在PHP8 中,match表達式是一種新的控制結構,用於根據表達式的值返回不同的結果。 1)它類似於switch語句,但返回值而非執行語句塊。 2)match表達式使用嚴格比較(===),提升了安全性。 3)它避免了switch語句中可能的break遺漏問題,增強了代碼的簡潔性和可讀性。

See all articles