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

編寫PHP擴充函數的參數

Nov 09, 2016 pm 02:45 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) 
    } 
php_printf("Hello "); 
    PHPWRITE(greeting, greeting_len); 
    php_printf(" "); 
    PHPWRITE(name, name_len);上面定義的參數,還有其它的三個參數來增強我們接收參數的能力,如下: 
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

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++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教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
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的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

See all articles