首頁 後端開發 php教程 [翻譯][php擴展開發與嵌入式]第6章-返回值

[翻譯][php擴展開發與嵌入式]第6章-返回值

Feb 09, 2017 am 11:40 AM

回傳值

用戶空間函數利用return關鍵字向它的調用空間回傳訊息, 這一點和C語言的語法相同.

例如:

function sample_long() {  
  return 42;  
}  
$bar = sample_long();
登入後複製

當sample_long()被調用時, 返回42並設定到$bar變數中. 在C語言中的等價代碼如下:

int sample_long(void) {  
  return 42;  
}  
void main(void) {  
  int bar = sample_long();  
}
登入後複製

當然, 在C語言中你總是知道被調用的函數是什麼, 並且基於函數原型返回, 因此相應的你要定義返回結果存儲的變數. 在php用戶空間處理時, 變數類型是動態的, 轉而依賴第2章"變數的里里外外"中介紹的zval的類型.

return_value變數

你可能認為你的內部函數應該直接返回一個zval, 或者說分配一個zval的內存空間並如下返回zval *.

PHP_FUNCTION(sample_long_wrong)  
{  
    zval *retval;  
  
    MAKE_STD_ZVAL(retval);  
    ZVAL_LONG(retval, 42);  
  
    return retval;  
}
登入後複製

不幸的是, 這樣做是不正確的. 並不是強制每個函數實現分配zval並返回它. 而是Zend引擎在函數呼叫之前預先分配這個空間. 接著將zval的類型初始化為IS_NULL, 並將值作為參數名稱return_value傳遞. 下面是正確的做法:

PHP_FUNCTION(sample_long)  
{  
    ZVAL_LONG(return_value, 42);  
    return;  
}
登入後複製

要注意的是PHP_FUNCTION()實現並不會直接傳回任何值. 取而代之的是直接將適當的資料彈出到return_value參數中, Zend引擎會在內部函數執行完成後處理它.

友情提示: ZVAL_LONG()宏是對多個賦值操作的一個封裝:

Z_TYPE_P(return_value) = IS_LONG;  
Z_LVAL_P(return_value) = 42;
登入後複製

或更直接點:

return_value->type = IS_LONG;  
return_value->value.lval = 42;
登入後複製

return_value的is_ref和refcount屬性不應該被內部函數直接修改. 這些值由Zend引擎在調用你的函數時初始化並處理.

現在我們來看看這個特殊的函數, 將它增加到第5章"你的第一個擴展"中創建的sample擴展中. 只需要在sample_hello_world()函數下面添加這個函數, 並將sample_long()加入到php_sample_functions結構體中:

static function_entry php_sample_functions[] = {  
    PHP_FE(sample_hello_world, NULL)  
    PHP_FE(sample_long, NULL)  
    { NULL, NULL, NULL }  
};
登入後複製

現在我們就可以執行make重新構建擴展了.

如果一切OK, 可以運行php並測試新函數:

$ php -r 'var_dump(sample_long());
登入後複製

包裝更緊湊的宏

在代碼可讀性和可維護性方面, ZVAL_*()巨集中有重複的部分: return_value變數. 這種情況下, 將宏的ZVAL替換為RETVAL, 我們就可以在呼叫時省略return_value了.

前面的例子中, sample_long()的實現代碼可以縮減到下面這樣:

PHP_FUNCTION(sample_long)  
{  
    RETVAL_LONG(42);  
    return;  
}
登入後複製

下表列出了Zend引擎中RETVAL一族的宏. 除了兩個特殊的, RETVAL宏除了刪除了return_value參數之外, 和對應的ZVAL族宏相同.

[翻譯][php擴展開發與嵌入式]第6章-返回值


要注意到, TRUE和FALSE宏沒有括號. 這是考慮到了Zend/PHP代碼標準的偏差, 保留了主要的一種以保持向後兼容. 如果你構建擴展失敗, 收到了錯誤消息undefined macro RETVAL_TRUE() , 請確認你是否在程式碼中寫這兩個宏時誤寫了括號.

通常, 在你的函數處理返回值的時候, 它已經準備好退出並將控制返回給調用作用域了. 由於這個原因, 為內部函數設計了另外一些宏用於返回: RETURN_*()族宏.

PHP_FUNCTION(sample_long)  
{  
    RETURN_LONG(42);  
}
登入後複製

儘管看不到, 但這個函數在RETURN_LONG()宏調用完後的確會返回. 我們可以在函數末尾增加php_printf()進行測試:

PHP_FUNCTION(sample_long)  
{  
    RETURN_LONG(42);  
    php_printf("I will never be reached.\n");  
}
登入後複製

php_printf(), 如內容所描述的, 因為RETURN_LONG()調用隱式的結束了函數.

🎜和RETVAL系列一樣, 前面表中列出的每個簡單類型都有函數.🎜🎜和RETVAL系列一樣, 前面表中列出的每個簡單類型都有對應的RETURN宏. 同樣和RETVAL系列一樣, RETURN_TRUE和RETURN_FALSE宏不使用括號.🎜🎜更加複雜的類型, 比如對象和數組, 同樣是通過return_value參數返回的; 然而, 它們天生就不能通過簡單宏的創建. 即使是資源類型, 雖然它有RETVAL宏, 但是真正要返回資源類型還需要額外的工作. 你將在第8章到第11章看到怎樣返回這些類型.🎜🎜值得這麼麻煩嗎?🎜🎜一個尚未使用的Zend內部函數特性是return_value_used參數. 考慮下面的用戶空間代碼:🎜
function sample_array_range() {  
    $ret = array();  
    for($i = 0; $i < 1000; $i++) {  
        $ret[] = $i;  
    }  
    return $ret;  
}  
sample_array_range();
登入後複製
🎜因為sample_array_range()調用的時候並沒有將結果存儲到變量中, 這裡創建使用的1000個元素的數組空間將被完全浪費. 當然, 這樣調用sample_array_range()是愚蠢的, 但是沒有很好的辦法預知未來你又能怎麼樣呢?🎜🎜雖然無法訪問用戶空間函數, 內部函數可以依賴於所有內部函數公共的return_value_used參數設定, 條件式的跳開這樣的無意義行為.🎜
PHP_FUNCTION(sample_array_range)  
{  
    if (return_value_used) {  
        int i;  
        /* 返回从0到999的数组 */  
        array_init(return_value);  
        for(i = 0; i < 1000; i++) {  
            add_next_index_long(return_value, i);  
        }  
        return;  
    } else {  
        /* 提示错误 */  
        php_error_docref(NULL TSRMLS_CC, E_NOTICE,  
               "Static return-only function called without processing output");  
        RETURN_NULL();  
    }  
}
登入後複製
🎜要看到這個函數的操作, 只需要在你的sample.c源文件中增加這個函數, 並將它暴露在php_sample_functions結構中:🎜
PHP_FE(sample_array_range, NULL)
登入後複製
🎜譯註: 關於用戶空間不使用的函數回傳值怎麼處理, 可以閱讀Zend/zend_vm_execute.h中的zend_do_fcall_common_helper_SPEC函數, 它在處理完內部函數呼叫後, 會檢查該函數的回傳值是否被使用, 如果不使用, 則進行了對應的釋放.🎜🎜回傳引用值🎜

从用户空间的php工作中你可能已经知道了, php函数还可以以引用方式返回值. 由于实现问题, 在php 5.1之前应该避免在内部函数中返回引用, 因为它不能工作. 考虑下面的用户空间代码片段:

function &sample_reference_a() {  
    /* 如果全局空间没有变量$a, 就以初始值NULL创建它 */  
    if (!isset($GLOBALS[&#39;a&#39;])) {  
        $GLOBALS[&#39;a&#39;] = NULL;  
    }  
    return $GLOBALS[&#39;a&#39;];  
}  
$a = &#39;Foo&#39;;  
$b = sample_reference_a();  
$b = &#39;Bar&#39;;
登入後複製

在这个代码片段中, 就像使用$b = &$GLOBALS['a];或者由于在全局空间, 使用$b = &$a; 将$b创建为$a的一个引用.

回顾第3章"内存管理", 在到达最后一行时, $a和$b实际上包含相同的值'Bar'. 现在我们看看内部实现这个函数:

#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && \  
                          PHP_MINOR_VERSION > 0)  
PHP_FUNCTION(sample_reference_a)  
{  
    zval **a_ptr, *a;  
  
  
    /* 从全局符号表查找变量$a */  
    if (zend_hash_find(&EG(symbol_table), "a", sizeof("a"),  
                                          (void**)&a_ptr) == SUCCESS) {  
        a = *a_ptr;  
    } else {  
        /* 如果不存在$GLOBALS[&#39;a&#39;]则创建它 */  
        ALLOC_INIT_ZVAL(a);  
        zend_hash_add(&EG(symbol_table), "a", sizeof("a"), &a,  
                                              sizeof(zval*), NULL);  
    }  
    /* 废弃旧的返回值 */  
    zval_ptr_dtor(return_value_ptr);  
    if (!a->is_ref && a->refcount > 1) {  
        /* $a需要写时复制, 在使用之前, 必选先隔离 */  
        zval *newa;  
        MAKE_STD_ZVAL(newa);  
        *newa = *a;  
        zval_copy_ctor(newa);  
        newa->is_ref = 0;  
        newa->refcount = 1;  
        zend_hash_update(&EG(symbol_table), "a", sizeof("a"), &newa,  
                                                 sizeof(zval*), NULL);  
        a = newa;  
    }  
    /* 将新的返回值设置为引用方式并增加refcount */  
    a->is_ref = 1;  
    a->refcount++;  
    *return_value_ptr = a;  
}  
#endif /* PHP >= 5.1.0 */
登入後複製

return_value_ptr参数是所有内部函数都会传递的另外一个公共参数, 它是zval **类型, 包含了指向return_value的指针. 通过在它上面调用zval_ptr_dtor(), 默认的return_value的zval *将被释放. 接着可以自由的选择一个新的zval *去替代它, 在这里选择了变量$a, 选择性的进行zval隔离后, 将它的is_ref设置为1, 设置到return_value_ptr中.

如果现在编译运行这段代码, 无论如何你会得到一个段错误. 为了使它可以工作, 你需要在php_sample.h中增加下面的代码:

#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && \  
                          PHP_MINOR_VERSION > 0)  
static  
    ZEND_BEGIN_ARG_INFO_EX(php_sample_retref_arginfo, 0, 1, 0)  
    ZEND_END_ARG_INFO ()  
#endif /* PHP >= 5.1.0 */
登入後複製

译注: 译者使用的php-5.4.9中, ZEND_BEGIN_ARG_INFO_EX的宏定义中已经包含了static修饰符, 因此本书示例中相应的需要进行修改, 请读者在阅读过程中注意这一点.

接着, 在php_sample_functions中声明你的函数时使用这个结构:

#if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && \  
                          PHP_MINOR_VERSION > 0)  
    PHP_FE(sample_reference_a, php_sample_retref_arginfo)  
#endif /* PHP >= 5.1.0 */
登入後複製

这个结构你将在本章后面详细学习, 用来向Zend引擎提供函数调用的重要暗示信息. 这里它告诉Zend引擎return_value需要被覆写, 应该从return_value_ptr中得到正确的地址. 如果没有这个暗示, Zend引擎会简单的在return_value_ptr中设置NULL, 这可能使得在执行到zval_ptr_dtor()时程序崩溃.

这段代码每一个片段都包裹在#if块中, 它指示编译器只有在PHP版本大于等于5.1时才启用这个支持. 如果没有这些条件指令, 这个扩展将不能在php4上编译(因为在return_value_ptr中包含的一些元素不存在), 在php5.0中不能提供正确的功能(有一个bug导致返回的引用被以值的方式拷贝)

引用方式返回值

使用return(语法)结构将值和变量回传给调用方是没有问题的, 但是, 有时你需要从一个函数返回多个值. 你可以使用数组(我们将在第8章"使用数组和哈希表工作")达到这个目的, 或者你可以使用参数栈返回值.

调用时引用传值

一种简单的引用传递变量方式是要求调用时在参数变量名前使用取地址符(&), 如下用户空间代码:

function sample_byref_calltime($a) {  
    $a .= &#39; (modified by ref!)&#39;;  
}  
$foo = &#39;I am a string&#39;;  
sample_byref_calltime(&$foo);  
echo $foo;
登入後複製

参数变量名前的取地址符(&)使得发送给函数的是$foo实际的zval, 而不是它的内容拷贝.这就使得函数可以通过传递的这个参数修改这个值来返回信息. 如果调用sample_byref_calltime()时没有在$foo前面使用取地址符(&), 则函数内的修改并不会影响原来的变量.

在C层面重演这个行为并不需要特殊的编码. 在你的sample.c源码文件中sample_long()后面创建下面的函数:

PHP_FUNCTION(sample_byref_calltime)  
{  
    zval *a;  
    int addtl_len = sizeof(" (modified by ref!)") - 1;  
  
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a) == FAILURE) {  
        RETURN_NULL();  
    }  
    if (!a->is_ref) {  
        /* 不是以引用方式传值则不做任何事离开函数 */  
        return;  
    }  
    /* 确保变量是字符串 */  
    convert_to_string(a);  
    /* 扩大a的缓冲区以使可以保存要追加的数据 */  
    Z_STRVAL_P(a) = erealloc(Z_STRVAL_P(a),  
        Z_STRLEN_P(a) + addtl_len + 1);  
    memcpy(Z_STRVAL_P(a) + Z_STRLEN_P(a),  
    " (modified by ref!)", addtl_len + 1);  
    Z_STRLEN_P(a) += addtl_len;  
}
登入後複製

和往常一样, 这个函数需要增加到php_sample_functions结构中.

PHP_FE(sample_byref_calltime,        NULL)
登入後複製

译注: 运行时引用传值在译者使用的版本(php-5.4.9 ZendEngine 2.4.0)中已经被完全废弃. 早前的版本可以在php.ini中使用allow_call_time_pass_reference指令启用. 测试时请注意版本问题.

编译期引用传值

更常用的方式是编译期引用传值. 这里函数的参数定义为只能以引用方式使用, 传递常量或其他中间值(比如函数调用的结果)将导致错误, 因为那样函数就没有地方可以存储结果值去回传了. 用户空间的编译期引用传值代码如下:

function sample_byref_compiletime(&$a) {  
    $a .= &#39; (modified by ref!)&#39;;  
}  
$foo = &#39;I am a string&#39;;  
sample_byref_compiletime($foo);  
echo $foo;
登入後複製

如你所见, 这和调用时引用传值的差别仅在于取地址符的位置不同. 在C的层面上去看这个函数时, 函数代码上是完全相同的. 唯一的区别在于php_sample_functions块中对函数的声明:

PHP_FE(sample_byref_compiletime, php_sample_byref_arginfo)
登入後複製

php_sample_byref_arginfo是一个常量结构, 你需要在使用之前先定义它.

实际上, 编译期引用传值中, 对is_ref检查的代码可以删除, 因为总能保证它是引用方式的. 不过这里留着它也不会有什么危害.

在Zend引擎1(php4)中, 这个结构是一个简单的char *列表, 第一个元素指定了长度, 接下来是描述每个函数参数的标记集合.

static unsigned char php_sample_byref_arginfo[] =  
                                { 1, BYREF_FORCE };
登入後複製

这里, 1表示向量只包含了一个参数的信息. 后面的元素就顺次描述参数特有的标记信息, 第二个元素描述第一个参数. 如果涉及到第二个或第三个参数, 对应的就需要在这个向量中增加第三个和第四个元素. 参数信息的可选值如下表:

[翻譯][php擴展開發與嵌入式]第6章-返回值

在Zend引擎2(php 5+)中, 你将使用一种更加可扩展的结构, 它包含类更多的信息, 比如最小和最大参数要求, 类型暗示, 是否强制引用等.

首先, 参数信息结构使用两个宏中的一个定义. 较简单的一个是ZEND_BEGIN_ARG_INFO(), 它需要两个参数:

ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference)
登入後複製

name非常简单, 就是扩展中其他地方使用这个结构时的名字, 当前这个例子我们使用的名字是: php_sample_byref_arginfo

pass_rest_by_reference的含义和BYREF_FORCE_REST用在Zend引擎1的参数信息向量最后一个元素时一致. 如果这个参数设置为1, 所有没有在结构中显式描述的参数都被认为是编译期引用传值的参数.

还有一种可选的开始宏, 它引入了两个Zend引擎1没有的新选项, 它是ZEND_BEGIN_ARG_INFO_EX():

ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference,  
                             required_num_args)
登入後複製

当然, name和pass_rest_by_reference和前面所说的是相同的含义. 本章前面也提到了, return_reference是告诉Zend你的函数需要用自己的zval覆写return_value_ptr.

最后一个参数, required_num_args, 它是另外一种类型的暗示, 用来告诉Zend在某种被认为是不完整的调用时完全的跳过函数调用.

在你拥有了一个恰当的开始宏后, 接下来就可以是0个或多个ZEND_ARG_*INFO元素. 这些宏的类型和用法如下表.

[翻譯][php擴展開發與嵌入式]第6章-返回值

最后, 所有使用Zend引擎2的宏设置的参数信息结构必须使用ZEND_END_ARG_INFO()结束. 对于你的sample函数, 你需要选择一个如下的结构:

ZEND_BEGIN_ARG_INFO(php_sample_byref_arginfo, 0)  
    ZEND_ARG_PASS_INFO(1)  
ZEND_END_ARG_INFO()
登入後複製

为了让扩展兼容Zend引擎1和2, 需要使用#ifdef语句为两者均定义arg_info结构:

#ifdef ZEND_ENGINE_2  
static  
    ZEND_BEGIN_ARG_INFO(php_sample_byref_arginfo, 0)  
        ZEND_ARG_PASS_INFO(1)  
    ZEND_END_ARG_INFO()  
#else /* ZE 1 */  
static unsigned char php_sample_byref_arginfo[] =  
                                { 1, BYREF_FORCE };  
#endif
登入後複製

注意, 这些代码片段是集中在一起的, 现在是时候创建一个真正的编译期引用传值实现了. 首先, 我们将为Zend引擎1和2定义的php_sample_byref_arginfo块放到头文件php_sample.h中.

接下来, 可以有两种选择, 一种是将PHP_FUNCTION(sample_byref_calltime)拷贝一份, 并重命名为PHP_FUNCTION(sample_byref_compiletime), 接着在php_sample_functions中增加一行PHP_FE(sample_byref_compiletime, php_sample_byref_arginfo)

这种方式简单移动, 并且在一段时候后修改时, 更加不容易产生混淆. 因为这里只是示例代码, 因此, 我们可以稍微放松点, 使用你在上一章学的PHP_FALIAS()避免代码重复.

这样, 就不是赋值PHP_FUNCTION(sample_byref_calltime), 而是在php_sample_functions中直接增加一行:

PHP_FALIAS(sample_byref_compiletime, sample_byref_calltime,  
    php_sample_byref_arginfo)
登入後複製

回顾第5章, 这将创建一个名为sample_byref_compiletime()的用户空间函数, 它对应的内部实现是sample_byref_calltime()的代码. php_sample_byref_arginfo是这个版本的特殊之处.

小结

本章你看到了怎样从一个内部函数返回值, 包括直接返回值和引用方式返回, 以及通过参数栈引用返回. 此外还简单了解了Zend引擎2的参数类型暗示结构zend_arg_info.

下一章你将会继续探究接受基本的zval参数以及使用zend_parse_parameters()强大的类型戏法.

以上就是 [翻译][php扩展开发和嵌入式]第6章-返回值的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡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 教程
1322
25
PHP教程
1270
29
C# 教程
1250
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與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

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

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

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

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