PHP弱语言,使用时不需要明确定义变量的类型。我大学时候接触都是C,C++,当自己去接触PHP的时候,就震惊不已,哇哇,啥啥,string 与 int 都可以相加,竟然还能通过去!!!!当时就对PHP底层对于数据操作这块很有兴趣,它到底有些啥奇技淫巧,能实现的这些不同类型之间的比较运算,算数运算。这里我们就要稍微讲一下,PHP两种方式:自动类型转换,强制类型转换
自动类型转换
Zend虚拟机在执行PHP代码会根据具体的应用场景进行转换,比如$a = "100"+200, 执行时Zend发现相加的是字符串,这个时候会尝试将“100”转换成数值类型(整型或浮点类型),装换时候不会改变原有值,而是产生一个新的变量来处理。
强制类型转换
比较运算符下的类型转换
涉及到类型转换,最多两个运算情况,应该是比较运算,算数运算,下面给在比较运算时,类型中情况,嘻嘻,这里就体现弱语言的一些不好的地方,但是通过强比较,过滤操作数据类型,这样代码习惯还是可以避免的~(PHP是世界上最好的语言,我也来自黑一下,哈哈)
先给出PHP在比较运算符下的类型转换规则下~ 图片来源截图php.net
1.对于字符串和数值类型,进行比较操作,需要转换成数值类型来进行比较,辣么字符串是怎么转换成数值类型,可以往下看我的转换成数值类型~
2.对于字符串中出现“e”字符的特殊字符串
3.比较运算符的比较规则,特别要注意两个数字的字符串来进行比较,进行的是数字比较
4.PHP类型比较表,松散比较,严格比较
场景A : 正数开头,拥有e字符,后续都是数字的字符串 和 整数类型0 比较
场景B: 不含e这样的特殊字符串与正整数 0
场景C :两个数字类型字符串,进行数字比较
场景D:PHP是否“0E”开头都解析为0来处理
0*10^111 = 0
var_dump("0E111" == "0000"); // true 的确是true 是因为转换成了数值比较 两者都是0
var_dump("0E111b" == 0 ); // true "0E111b"=>0*10^111 = 0 转换成了数值类型,所以两者相等
var_dump("0E111b" == "0000"); //false 因为两者都是字符串进行的是词汇比较
所以不是所有“0E”开头字符串都解析为0来处理,而是看两者进行的是什么比较类型。
//file zend_operators.c
ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
{
if (Z_TYPE_P(op) == IS_OBJECT) {
if (Z_OBJ_HT_P(op)->cast_object) {
//如果是转化是一个对象,且定义了handler,则调用
zval org;
ZVAL_COPY_VALUE(&org, op);
if (Z_OBJ_HT_P(op)->cast_object(&org, op, IS_NULL) == SUCCESS) {
zval_dtor(&org);
return;
}
ZVAL_COPY_VALUE(op, &org);
}
}
//销毁zval,将类型设置为NULL
zval_ptr_dtor(op);
ZVAL_NULL(op);
}
当要转换成布尔类型时,根据原值的true,false决定结果,下面值被认为是false,其他情况被认为true,比如资源,对象。
//file zend_operators.c
ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
{
return i_zend_is_true(op);
}
static zend_always_inline int i_zend_is_true(zval *op)
{
int result = 0;
again:
switch (Z_TYPE_P(op)) {
case IS_TRUE:
result = 1;
break;
case IS_LONG:
//非0既真
if (Z_LVAL_P(op)) {
result = 1;
}
break;
case IS_DOUBLE:
if (Z_DVAL_P(op)) {
result = 1;
}
break;
case IS_STRING:
//非空字符串及“0”外都为true
if (Z_STRLEN_P(op) > 1 || (Z_STRLEN_P(op) && Z_STRVAL_P(op)[0] != '0')) {
result = 1;
}
break;
case IS_ARRAY:
//非空数组即为true
if (zend_hash_num_elements(Z_ARRVAL_P(op))) {
result = 1;
}
break;
case IS_OBJECT:
//默认返回true
result = zend_object_is_true(op);
break;
case IS_RESOURCE:
//合法资源返回true
if (EXPECTED(Z_RES_HANDLE_P(op))) {
result = 1;
}
break;
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto again;
break;
default:
break;
}
return result;
}
浮点类型的转换与整形差不多,所以这里合在一起了,单看整形的源码。其他类型转换为整型的规则
//file zend_operators.c
ZEND_API zend_long ZEND_FASTCALL _zval_get_long_func(zval *op) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_NULL:
case IS_FALSE:
return 0;
case IS_TRUE:
return 1;
case IS_RESOURCE:
//资源转为zend_resource->handler
return Z_RES_HANDLE_P(op);
case IS_LONG:
return Z_LVAL_P(op);
case IS_DOUBLE:
return zend_dval_to_lval(Z_DVAL_P(op));
case IS_STRING:
//字符串转为strtol()处理 10代表着10进制
return ZEND_STRTOL(Z_STRVAL_P(op), NULL, 10);
case IS_ARRAY:
//数组是否为空,转化0,1
return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
case IS_OBJECT:
{
zval dst;
convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
if (Z_TYPE(dst) == IS_LONG) {
return Z_LVAL(dst);
} else {
//默认为1
return 1;
}
}
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
}
return 0;
}
//strtol宏定义,就是在这里进行字符串的转化啦,对于数组开头的字符串这里将使用10进制来进行,转化,base取值范围为了2~36进制之间,或者是特殊值0
# define ZEND_STRTOL(s0, s1, base) strtol((s0), (s1), (base))
下面是字符串转化的规则
//file zend_operators.c
ZEND_API zend_string* ZEND_FASTCALL _zval_get_string_func(zval *op) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_UNDEF:
case IS_NULL:
case IS_FALSE:
return ZSTR_EMPTY_ALLOC();
case IS_TRUE:
if (CG(one_char_string)['1']) {
return CG(one_char_string)['1'];
} else {
return zend_string_init("1", 1, 0);
}
case IS_RESOURCE: {
char buf[sizeof("Resource id #") + MAX_LENGTH_OF_LONG];
int len;
len = snprintf(buf, sizeof(buf), "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
return zend_string_init(buf, len, 0);
}
case IS_LONG: {
return zend_long_to_str(Z_LVAL_P(op));
}
case IS_DOUBLE: {
return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
}
case IS_ARRAY:
zend_error(E_NOTICE, "Array to string conversion");
return zend_string_init("Array", sizeof("Array")-1, 0);
case IS_OBJECT: {
zval tmp;
if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
return Z_STR(tmp);
}
} else if (Z_OBJ_HT_P(op)->get) {
zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
if (Z_TYPE_P(z) != IS_OBJECT) {
zend_string *str = zval_get_string(z);
zval_ptr_dtor(z);
return str;
}
zval_ptr_dtor(z);
}
zend_error(EG(exception) ? E_ERROR : E_RECOVERABLE_ERROR, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
return ZSTR_EMPTY_ALLOC();
}
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;
case IS_STRING:
return zend_string_copy(Z_STR_P(op));
EMPTY_SWITCH_DEFAULT_CASE()
}
return NULL;
}
还有转换成数组,对象两种的源码,没有说明。对于字符串,布尔值,整型转成数组,都是变成数组的单个元素,对象变成数组,对象的属性变成数组的键名,同理对象也差不多是这样~ 哈哈,原谅我偷一点点的懒,有时间一定补一定补!!!每天起床都给自己打口气~