PHP内核函数研究之 intval[原创]
作者 斯人 | 发布于 2012 年 4 月 8 日
PHP PHP内核

趁热打铁 顺便说说 intval函数.该函数好像我们用的最多的就是在POST或者GET某个参数的时候,将其强制转换为int型,
为了保证我们传入到SQL的时候是一个整形.,当然这只是其中一种用法..
该函数接受两个参数,第一个是要转换的字符串,第二个要转换成的进制数,默认为十进制.
我们先用PHP 来看看它的用法.

class a{
    public $b;
    function c(){
        
    }
}
$a=new a();
echo intval($a); //输出1.
$a=array('a'=>1,'b'=>2);
echo intval($a);//输出1
$a=false;
echo intval($a);//输出0
$a=true;
echo intval($a);//输出1
$a=1.9;
echo intval($a);//输出1
$a=null;
echo intval($a);//输出0

OK,看看它的定义.
同样定义在ext/standard/type.c文件中.

PHP_FUNCTION(intval)
{
        zval **num;
        long arg_base;
        int base;

        switch (ZEND_NUM_ARGS()) {
                case 1:
                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &num) == FAILURE) {
                                return;
                        }
                        base = 10;
                        break;

                case 2:
                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &num, &arg_base) == FAILURE) {
                                return;
                        }
                        base = arg_base;
                        break;

                default:
                        WRONG_PARAM_COUNT;
        }

        RETVAL_ZVAL(*num, 1, 0);
        convert_to_long_base(return_value, base);
}

该函数会根据我们传递过来的参数个数进行不同的处理.第二个参数是要转换成的进制数,如果为空默认为10进制.
最后会调用 convert_to_long_base(return_value, base);来对我们输入过来的数据进行处理
该函数定义在Zend/zend_operators.c中

ZEND_API void convert_to_long_base(zval *op, int base) /* {{{ */
{       
        long tmp;               

        switch (Z_TYPE_P(op)) {
                case IS_NULL:
                        Z_LVAL_P(op) = 0;
                        break;  
                case IS_RESOURCE: {
                                TSRMLS_FETCH();
                
                                zend_list_delete(Z_LVAL_P(op));
                        }
                        /* break missing intentionally */
                case IS_BOOL:
                case IS_LONG:
                        break;
                case IS_DOUBLE:
                        Z_LVAL_P(op) = zend_dval_to_lval(Z_DVAL_P(op));
                        break;
                case IS_STRING:
                        {
                                char *strval = Z_STRVAL_P(op);

                                Z_LVAL_P(op) = strtol(strval, NULL, base);
                                STR_FREE(strval);
                        }
                        break;
                case IS_ARRAY:
                        tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
                        zval_dtor(op);
                        Z_LVAL_P(op) = tmp;
                        break;
                case IS_OBJECT:
                            {
                                int retval = 1;
                                TSRMLS_FETCH();

                                convert_object_to_type(op, IS_LONG, convert_to_long);

                                if (Z_TYPE_P(op) == IS_LONG) {
                                        return;
                                }
                                zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);

                                zval_dtor(op);
                                ZVAL_LONG(op, retval);
                                return;
                        }
                default:
                        zend_error(E_WARNING, "Cannot convert to ordinal value");
                        zval_dtor(op);
                        Z_LVAL_P(op) = 0;
                        break;
        }

        Z_TYPE_P(op) = IS_LONG;
}

该函数首先获取类型,在进行不同的处理
19行,如果是 IS_DOUBLE类型,则会进行强制转换# define zend_dval_to_lval(d) ((long) (d))
21-27行,会调用 C函数 strtol将其转换成long类型
29-33行,如果是数组类型,会获取数组的个数,如果有值则将其设置为1,否则为0.这就是我们数组里有N个键和值,为什么返回还是1的原因:
不管 数组键值有多少个,只要有值,就为1.
34-49行,如果是对象呢,那就会先调用convert_to_long其强制转换为long,否则抛出异常,返回1.
如果没有返回类型则会返回0.

原文出处:http://www.imsiren.com/archives/520