摘要:轉載自我的博客在眾多的新特性中,我覺得這是最神奇甚至是詭異的一個,如果有不理解這個概念的朋友,可能連它的說明都看不懂。在這個例子中操作符被重載為,操作符被重載為。再重載成操作符,以后咋跟蹤代碼。。。
轉載自我的博客:http://70.io/2014/03/php-5_6-internal-operator-overloading
在眾多php 5.6的新特性中,我覺得這是最神奇甚至是詭異的一個,如果有不理解這個概念的朋友,可能連它的說明都看不懂 https://wiki.php.net/rfc/operator_overloading_gmp。
首先要說明的是,這個重載不影響到userland,也就是我們不用關心它是怎么重載的,只用關心怎么使用,它的實現是在php內核代碼中。
在上面的php說明網址中,它舉了一個對gmp_*模塊重載后的例子
// 重載前的代碼 $result = gmp_mod( gmp_add( gmp_mul($c0, gmp_mul($ms0, gmp_invert($ms0, $n0))), gmp_add( gmp_mul($c1, gmp_mul($ms1, gmp_invert($ms1, $n1))), gmp_mul($c2, gmp_mul($ms2, gmp_invert($ms2, $n2))) ) ), gmp_mul($n0, gmp_mul($n1, $n2)) ); // 重載后的代碼 $result = ( $c0 * $ms0 * gmp_invert($ms0, $n0) + $c1 * $ms1 * gmp_invert($ms1, $n1) + $c2 * $ms2 * gmp_invert($ms2, $n2) ) % ($n0 * $n1 * $n2);
如果你會一點scala類似的語言,就能很好地理解了。在這個例子中+操作符被重載為gmp_add,*操作符被重載為gmp_mull。以前的基于函數式的代碼讓很多算法上的細節無法展現出來,改成基于操作符的就很好理解了。
它是怎么實現的呢?讓我們來跟蹤一下這個patch修改的源代碼,https://github.com/php/php-src/pull/342/files。最好先關注Zend/zend_operators.c這個文件的修改,基本上邏輯就很清晰了,比如ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)這個函數,它處理了php中的加號+運算(前面帶+的兩行是這個patch增加的內容)
default: if (!converted) { + ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB); + zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1;
if(!converted)判斷了左右操作數還沒有轉換為number時候的處理,在以前是調用zendi_convert_scalar_to_number直接將其轉換為number然后再SUB,現在在前面加了個宏ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB),這個宏的實現細節是
#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { return SUCCESS; } } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { return SUCCESS; } }
它先判斷左操作數是否為一個OBJECT,并且這個OBJECT內部定義了運算符操作的重載實現,如果是那么就調用這個handler來處理這次操作符運算,如果左操作數不符合這些條件,再對右操作數做一次這些判斷,基本上$a + $b你就可以理解為以下偽代碼
if ($a instanceof GMP && method_exists($a, "add")) { $a->add($b); } else if ($b instanceof GMP && method_exists($b, "add")) { $b->add($a); }
好吧,最后我來談談我的看法,之所以我對這個改進感到詭異是因為,它對一般的web開發基本沒啥用,其影響基本是很少用到的數學運算模塊。而且由于這個改進跟userland沒啥關系,所以我們在php代碼中也用不了,別指望你能像scala那樣在class里定義操作符的實現,這完全是兩碼事。
你只能指望這些模塊或者擴展的作者實現了,而且最后實現也沒有一個統一的標準,本來php的函數命名就夠混亂了。。。再重載成操作符,以后咋跟蹤代碼。。。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/20695.html
摘要:類與對象基本概念如果在之后跟著的是一個包含有類名的字符串,則該類的一個實例被創建。如果該類屬于一個名字空間,則必須使用其完整名稱。如果一個類被聲明為,則不能被繼承。命名空間通過關鍵字來聲明。 類與對象 基本概念 new:如果在 new 之后跟著的是一個包含有類名的字符串,則該類的一個實例被創建。如果該類屬于一個名字空間,則必須使用其完整名稱。 Example #3 創建一個實例 ...
摘要:例如汽車這個名詞可以理解為汽車的總類,但這輛寶馬汽車則是一個具體的汽車對象。當在類成員方法內部調用的時候,可以使用偽變量調用當前對象的屬性。在面向對象中則被稱之為方法。 簡述 現在大伙都在講面向對象編程,但是我們也得先找著一個對象是不?不然怎么面向對象?怎么編程? --- 笑話一則,但是理不虧,要搞P面向對象編程,我們起碼要先搞懂對象(還有類)是什么?只有了解它,理解它,你才能駕馭它。...
摘要:然而,兩個重要的已經獲得通過,它們將帶來一些期望已久的內部與用戶層的一致性。綜合比較運算符我個人最喜歡的新增特性是綜合比較運算符,,也稱為飛船操作符。實際上,該操作符的工作方式與,或基本一致。 這是我們期待已久的 PHP 7 系列文章的第一篇。 或許你已經知道了,我在?PHP 5.0.0 時間軸?提的 RFC (Request For Comments)通過了, PHP 7 成為 PH...
摘要:同時還支持簡寫的運算符,表示進行冪運算并賦值。對應的結構為和。為了達到一致性將添加函數。新增函數可用來返回數組中指定的一列。這種簡寫形式被稱為在起被默認開啟,在起總是可用。三元運算符可以簡寫省略中間的部分表達式,當為時返回,否則返回。 PHP 5.6 1、可以使用表達式定義常量 https://php.net/manual/zh/migration56.new-features.p...
摘要:同時還支持簡寫的運算符,表示進行冪運算并賦值。為了達到一致性將添加函數。新增函數可用來返回數組中指定的一列。這種簡寫形式被稱為在起被默認開啟,在起總是可用。結構中可以用雙引號來聲明標識符了。 PHP 5.61、可以使用表達式定義常量 https://php.net/manual/zh/mig... 在之前的 PHP 版本中,必須使用靜態值來定義常量,聲明屬性以及指定函數參數默認值。 現...
閱讀 2613·2021-11-02 14:39
閱讀 4338·2021-10-11 10:58
閱讀 1465·2021-09-06 15:12
閱讀 1850·2021-09-01 10:49
閱讀 1334·2019-08-29 18:31
閱讀 1889·2019-08-29 16:10
閱讀 3343·2019-08-28 18:21
閱讀 877·2019-08-26 10:42