最近瀏覽PHP語言的源碼-比較函數php
其實我說的比較函數不是字符串比較,並且當我用PHP 的數組排序時候須要比較函數web
1,爲何用比較函數數組
首先用比較函數的好處就是代碼的抽象,其實就是隻有知足比較函數的規則你就能夠,按照你本身方式排序,不是降序和升序這些簡單的規則!知足規則{-1,0,1}-1:表明是小於,0表明等於,1表明大小app
2.用比較函數tcp
ZEND_API int compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ { int ret; int converted = 0; zval op1_copy, op2_copy; zval *op_free, tmp_free; while (1) { switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { case TYPE_PAIR(IS_LONG, IS_LONG): ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0)); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_LONG): Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); return SUCCESS; case TYPE_PAIR(IS_LONG, IS_DOUBLE): Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); return SUCCESS; case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE): if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) { ZVAL_LONG(result, 0); } else { Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result))); } return SUCCESS; case TYPE_PAIR(IS_ARRAY, IS_ARRAY): ZVAL_LONG(result, zend_compare_arrays(op1, op2)); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_NULL): case TYPE_PAIR(IS_NULL, IS_FALSE): case TYPE_PAIR(IS_FALSE, IS_NULL): case TYPE_PAIR(IS_FALSE, IS_FALSE): case TYPE_PAIR(IS_TRUE, IS_TRUE): ZVAL_LONG(result, 0); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_TRUE): ZVAL_LONG(result, -1); return SUCCESS; case TYPE_PAIR(IS_TRUE, IS_NULL): ZVAL_LONG(result, 1); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_STRING): if (Z_STR_P(op1) == Z_STR_P(op2)) { ZVAL_LONG(result, 0); return SUCCESS; } ZVAL_LONG(result, zendi_smart_strcmp(op1, op2)); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_STRING): ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_STRING): ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_NULL): ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1); return SUCCESS; case TYPE_PAIR(IS_OBJECT, IS_NULL): ZVAL_LONG(result, 1); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_OBJECT): ZVAL_LONG(result, -1); return SUCCESS; default: if (Z_ISREF_P(op1)) { op1 = Z_REFVAL_P(op1); continue; } else if (Z_ISREF_P(op2)) { op2 = Z_REFVAL_P(op2); continue; } if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) { return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2); } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) { return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2); } if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) { if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) { /* object handles are identical, apparently this is the same object */ ZVAL_LONG(result, 0); return SUCCESS; } if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) { ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2)); return SUCCESS; } } if (Z_TYPE_P(op1) == IS_OBJECT) { if (Z_OBJ_HT_P(op1)->get) { zval rv; op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); ret = compare_function(result, op_free, op2); zend_free_obj_get_result(op_free); return ret; } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { ZVAL_UNDEF(&tmp_free); if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) { ZVAL_LONG(result, 1); zend_free_obj_get_result(&tmp_free); return SUCCESS; } ret = compare_function(result, &tmp_free, op2); zend_free_obj_get_result(&tmp_free); return ret; } } if (Z_TYPE_P(op2) == IS_OBJECT) { if (Z_OBJ_HT_P(op2)->get) { zval rv; op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); ret = compare_function(result, op1, op_free); zend_free_obj_get_result(op_free); return ret; } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { ZVAL_UNDEF(&tmp_free); if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) { ZVAL_LONG(result, -1); zend_free_obj_get_result(&tmp_free); return SUCCESS; } ret = compare_function(result, op1, &tmp_free); zend_free_obj_get_result(&tmp_free); return ret; } else if (Z_TYPE_P(op1) == IS_OBJECT) { ZVAL_LONG(result, 1); return SUCCESS; } } if (!converted) { if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) { ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0); return SUCCESS; } else if (Z_TYPE_P(op2) == IS_NULL || Z_TYPE_P(op2) == IS_FALSE) { ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0); return SUCCESS; } else if (Z_TYPE_P(op1) == IS_TRUE) { ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1); return SUCCESS; } else if (Z_TYPE_P(op2) == IS_TRUE) { ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1); return SUCCESS; } else { zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); converted = 1; } } else if (Z_TYPE_P(op1)==IS_ARRAY) { ZVAL_LONG(result, 1); return SUCCESS; } else if (Z_TYPE_P(op2)==IS_ARRAY) { ZVAL_LONG(result, -1); return SUCCESS; } else if (Z_TYPE_P(op1)==IS_OBJECT) { ZVAL_LONG(result, 1); return SUCCESS; } else if (Z_TYPE_P(op2)==IS_OBJECT) { ZVAL_LONG(result, -1); return SUCCESS; } else { ZVAL_LONG(result, 0); return FAILURE; } } } }
3.總結ide
其實通常人認爲比較函數很簡單:就返回-1,0,1比較能夠嗎,爲何寫的那麼長。首選,php是弱類型語言,咱們不能肯定咱們要比較兩個數 是什麼類型,好比數字,數字又分整型,浮點型,長整型,字符串,空等因而就註定長PHP的2個PHP的類型的個數= 2^(PHP類型的個數)函數
這就是一門語言,受歡迎的語言,考慮的方面比較多,全面性,this
一門語言存在時間越長越長,它的補丁就越多,這個是在實踐中檢驗出來的!你問它爲何,有可能它也不知道,反正就這樣這個問題能夠避免,有可能爲了環境,你確定見過#if HAVE_STRCOLL #endif 等等,也有可能避免它用函數的bug,也有可能每次對代碼的抽象的不一樣,反正就源碼就是一個難懂,難懂後面你能夠看到一門語言的背後的故事,其實底層和咱們作應用層原理同樣,就是經過已有創造出咱們想要東西,好比應用層:咱們能夠用php語言寫一個web頁面,底層只不過用c語言寫一個tcp/ip 的寫協議,scala