php比較関数

12002 ワード

最近PHP言語のソースコード-比較関数をブラウズしました
実は私が言った比較関数は文字列比較ではなく、PHPの配列でソートするときに比較関数が必要です.
1、なぜ比較関数を使うのか
まず比較関数を使うメリットはコードの抽象で、実は比較関数の規則を満たすだけで、あなた自身の方法でソートすることができて、降順と昇順のこれらの簡単な規則ではありません!ルールを満たす{-1,0,1}-1:より小さい、0は等しい、1はサイズを表す
2.比較関数で
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.まとめ
実は一般の人は比較関数が簡単だと思っています:-1,0,1を返して比較してもいいですか、どうしてそんなに長く書いていますか.第一に、phpは弱いタイプの言語で、私達は2つの数がどんなタイプなのかを比較することができなくて、例えば数字、数字はまた型を分けて、浮動小数点型、長い型、文字列、空は長いPHPの2つのPHPのタイプの個数=2^(PHPのタイプの個数)に等しいです
これは一つの言語で、人気のある言語で、考慮の方面は比較的に多くて、全面性、
一つの言語の存在時間が長ければ長いほど、パッチが多くなります.これは実践の中で検証されています.なぜかと聞くと、知らないかもしれませんが、どうせこのような問題は避けることができます.環境のために、あなたはきっと#if HAVEを見たことがあります.STRCOLL#endifなどは、関数のバグを避けることもできるし、コードの抽象的な違いを避けることもできる.例えばアプリケーション層:php言語でwebページを書くことができます.下位層はc言語でtcp/ipの書き込みプロトコルを書くだけです.