当前位置:首页 > PHP教程 > php应用 > 列表

PHP类型转换的面试题与答案解析

发布:smiling 来源: PHP粉丝网  添加日期:2015-12-24 13:21:02 浏览: 评论:0 

面试题对于我们要去找工作的朋友多少都会要看一下的,这里php粉丝网为各位整理PHP类型转换的面试题与答案解析,希望本文章能够对各位有帮助。

最近在为公司面试新人,经常会问到的一道题目就是PHP类型转换的值,例如:

  1. var_dump((int)true); 
  2. var_dump((string)true); 
  3. var_dump((string)false); 
  4. var_dump((bool)"1"); 
  5. var_dump((bool)"0"); 
  6. var_dump((bool)""); 
  7. var_dump((bool)"false"); 

我印象中最早见到这道题目是在英极的PHP高级开发工程师岗位的笔试题里面,看似很基础,但是依然可以难住不少PHPer。先来看一下运行结果:

  1. int(1) 
  2. string(1) "1" 
  3. string(0) "" 
  4. bool(true) 
  5. bool(false) 
  6. bool(false) 
  7. bool(true) 

对于大多数人来说,第1、2、4行通常是没有问题的。但是为什么false转换为字符串是空字符串呢?在处理请求值时,通常会传一个字符串类型的false,但是“false”(字符串)并非false(布尔),这有点令人疑惑了。

为什么会这样呢?

关于这个问题,我们从PHP内核入手,看看在类型转换时系统内部到底发生了什么。

首先补充一些关于PHP弱类型实现方式的背景知识。PHP解释器是使用C语言写成的,当然最终对变量的处理,也会使用C语言构造数据结构来实现。在Zend引擎中,一个PHP变量对应的类型是zval。

打开Zend/zend_types.h文件,我们可以看到zval类型的定义,php-5.5.23版本大约在第55行左右:

typedef struct _zval_struct zval;

这样我们发现,zval其实是一个名为_zval_struct的结构体类型,我们在Zend/zend.h文件中找到这个结构体的定义,大约在320行左右开始:

  1. typedef union _zvalue_value { 
  2. long lval; /* long value */ 
  3. double dval; /* double value */ 
  4. struct { 
  5. char *val; 
  6. int len; 
  7. } str; 
  8. HashTable *ht; /* hash table value */ 
  9. zend_object_value obj; 
  10. } zvalue_value; 
  11. //phpfensi.com 
  12. struct _zval_struct { 
  13. /* Variable information */ 
  14. zvalue_value value; /* value */ 
  15. zend_uint refcount__gc; 
  16. zend_uchar type; /* active type */ 
  17. zend_uchar is_ref__gc; 
  18. }; 

大家可以看到,_zval_struct中包含两个重要的成员,一个是zvalue_value类型的value,一个是zend_uchar类型的type。注意zvalue_value类型是一个联合体,它用来存储一个PHP变量的值的信息。(如果你忘记了什么是联合体,我来解释一下。联合体类似结构体,但是联合体的中的成员,存储时有且只能有一个,而且联合体占用的空间是联合体中长度最长的那个成员,这样做是为了节省内存的使用。)在zvalue_value中,包括了long、double、struct、HashTable、zend_object_value五个类型的成员。他们分别用来存储PHP变量不同类型的值:

  1. C类型  PHP类型 
  2. long  bool 
  3. int 
  4. resource 
  5. double  float 
  6. struct  string 
  7. HashTable  array 
  8. zend_object_value  object 

看到这个结构体之后,想必也就明白了常问的诸如PHP中int类型的取值范围,以及php中strlen的时间复杂度之类的问题。

由此可见,PHP的变量类型转换,或者说是弱类型实现,本质上是实现zval类型在不同类型之间的转换。除了完成zvalue_value的数值转换,还需要将_zval_struct中的type设置成当前变量的type类型,在Zend引擎中实现了convert_to_*系列函数完成这一转换,我们在Zend/zend_operators.c中可以看到这些转换函数,在大约511行左右,可以找到转换为布尔类型的函数:

  1. ZEND_API void convert_to_boolean(zval *op) /* {{{ */ 
  2. int tmp; 
  3.  
  4. switch (Z_TYPE_P(op)) { 
  5. case IS_BOOL
  6. break
  7. case IS_NULL
  8. Z_LVAL_P(op) = 0; 
  9. break
  10. case IS_RESOURCE: { 
  11. TSRMLS_FETCH(); 
  12.  
  13. zend_list_delete(Z_LVAL_P(op)); 
  14. /* break missing intentionally */ 
  15. case IS_LONG
  16. Z_LVAL_P(op) = (Z_LVAL_P(op) ? 1 : 0); 
  17. break
  18. case IS_DOUBLE
  19. Z_LVAL_P(op) = (Z_DVAL_P(op) ? 1 : 0); 
  20. break
  21. case IS_STRING
  22. char *strval = Z_STRVAL_P(op); 
  23.  
  24. if (Z_STRLEN_P(op) == 0 
  25. || (Z_STRLEN_P(op)==1 && Z_STRVAL_P(op)[0]=='0')) { 
  26. Z_LVAL_P(op) = 0; 
  27. else { 
  28. Z_LVAL_P(op) = 1; 
  29. STR_FREE(strval); 
  30. break
  31. case IS_ARRAY
  32. tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0); 
  33. zval_dtor(op); 
  34. Z_LVAL_P(op) = tmp; 
  35. break
  36. case IS_OBJECT
  37. zend_bool retval = 1; 
  38. TSRMLS_FETCH(); 
  39.  
  40. convert_object_to_type(op, IS_BOOL, convert_to_boolean); 
  41.  
  42. if (Z_TYPE_P(op) == IS_BOOL) { 
  43. return
  44.  
  45. zval_dtor(op); 
  46. ZVAL_BOOL(op, retval); 
  47. break
  48. default
  49. zval_dtor(op); 
  50. Z_LVAL_P(op) = 0; 
  51. break
  52. Z_TYPE_P(op) = IS_BOOL
  53. /* }}} */ 

case IS_STRING这段代码即是将一个字符串类型变量转换为布尔型的操作。可以看到,只有空字符串,或者字符串长度为1,并且此字符为0时,字符串的布尔值才为1,也就是true,其他为0,也就是false。

同样的,我们也就明白了布尔值如何转换为字符串的,可以从_convert_to_string函数的实现中了解。

看似简单并且基础的PHP问题,究其根源是对PHP实现机制的把握。个人觉得,这道题也不失为鉴别PHPer知识边界的一道好题目。

Tags: PHP类型转换 PHP面试题

分享到: