函數的參數
最簡單的取得函數呼叫者傳遞過來的參數就是使用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()作為參數。

PHP是一種服務器端腳本語言,用於動態網頁開發和服務器端應用程序。 1.PHP是一種解釋型語言,無需編譯,適合快速開發。 2.PHP代碼嵌入HTML中,易於網頁開發。 3.PHP處理服務器端邏輯,生成HTML輸出,支持用戶交互和數據處理。 4.PHP可與數據庫交互,處理表單提交,執行服務器端任務。

PHP在過去幾十年中塑造了網絡,並將繼續在Web開發中扮演重要角色。 1)PHP起源於1994年,因其易用性和與MySQL的無縫集成成為開發者首選。 2)其核心功能包括生成動態內容和與數據庫的集成,使得網站能夠實時更新和個性化展示。 3)PHP的廣泛應用和生態系統推動了其長期影響,但也面臨版本更新和安全性挑戰。 4)近年來的性能改進,如PHP7的發布,使其能與現代語言競爭。 5)未來,PHP需應對容器化、微服務等新挑戰,但其靈活性和活躍社區使其具備適應能力。

PHP的核心優勢包括易於學習、強大的web開發支持、豐富的庫和框架、高性能和可擴展性、跨平台兼容性以及成本效益高。 1)易於學習和使用,適合初學者;2)與web服務器集成好,支持多種數據庫;3)擁有如Laravel等強大框架;4)通過優化可實現高性能;5)支持多種操作系統;6)開源,降低開發成本。

PHP沒有死。 1)PHP社區積極解決性能和安全問題,PHP7.x提升了性能。 2)PHP適合現代Web開發,廣泛用於大型網站。 3)PHP易學且服務器表現出色,但類型系統不如靜態語言嚴格。 4)PHP在內容管理和電商領域仍重要,生態系統不斷進化。 5)通過OPcache和APC等優化性能,使用OOP和設計模式提升代碼質量。

PHP和Python各有優劣,選擇取決於項目需求。 1)PHP適合Web開發,易學,社區資源豐富,但語法不夠現代,性能和安全性需注意。 2)Python適用於數據科學和機器學習,語法簡潔,易學,但執行速度和內存管理有瓶頸。

PHP用於構建動態網站,其核心功能包括:1.生成動態內容,通過與數據庫對接實時生成網頁;2.處理用戶交互和表單提交,驗證輸入並響應操作;3.管理會話和用戶認證,提供個性化體驗;4.優化性能和遵循最佳實踐,提升網站效率和安全性。

PHP在數據庫操作和服務器端邏輯處理中使用MySQLi和PDO擴展進行數據庫交互,並通過會話管理等功能處理服務器端邏輯。 1)使用MySQLi或PDO連接數據庫,執行SQL查詢。 2)通過會話管理等功能處理HTTP請求和用戶狀態。 3)使用事務確保數據庫操作的原子性。 4)防止SQL注入,使用異常處理和關閉連接來調試。 5)通過索引和緩存優化性能,編寫可讀性高的代碼並進行錯誤處理。

在PHP中使用預處理語句和PDO可以有效防範SQL注入攻擊。 1)使用PDO連接數據庫並設置錯誤模式。 2)通過prepare方法創建預處理語句,使用佔位符和execute方法傳遞數據。 3)處理查詢結果並確保代碼的安全性和性能。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

WebStorm Mac版
好用的JavaScript開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Dreamweaver Mac版
視覺化網頁開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。