前言
曾经在项目开发过程中,有一天,我遇到了一个神奇的问题,乍一看之下:明明没问题的,却跑出来的结果完全不对。甚至一度怀疑是不是PHP有BUG被我发现了。事实证明,是我错了,错在误把字符串当数组使用。虽然当初知道现象,也解决了问题,但对于当时所发生的始末,仍然是一支半解。后来经过总结提炼,才得知原来是其中的关系的如此微妙,觉得非常有趣,也很能考究对PHP这门语言的把握程度。
于是就有了这道PHP面试题 ——
两行代码的PHP面试题
请问,你觉得以下代码会输出什么,并解释为什么。
正确答案是?
如果你不通过执行上面代码,就能说出正确的答案,至少说明:
- 你是一个细心的人
- 对PHP语言的理解非常到位
但实际情况是,在面试过程中,很多人都回答不出正确的答案,更无从解释其中的原由。
回答最多的错误答案
回答最多的答案(但是错误的),是:输出一个数组,即:array('dogstar')。他们认为,把一个字符串当作数组使用时,会把这个变量转换为一个数组类型,从而得到这个结果。
这时候,我是表示很怀疑的,怀疑他是不是把以前所学的编程语言知识都丢了,或者根本没上过相应的课程逃课去泡妞了。把指针下的某个下标进行赋值,会改变当前指针所指的变量类型?
本文作者:dogstar,如需要转载,请注明出处,谢谢。
可能的错误答案
也有人说直接挂掉,但这种说法并不多。
解题过程细说
要想得知最终正确的答案,至少需要对PHP的字符串和数组有较为深刻的理解,以及PHP基本类型和变量的底层知识有一定的认识。
可以把这道题,当作一道高中时代的方程式,一步步进行分解、拆解、转换,便可慢慢水落石出,最终得到正确的答案。而不是不加思索就断言结果是什么。
编程语言,以及计算机都是理性的,更多是靠逻辑和推理,是客观的事实,而不是靠主观臆断。
首先,第一行代码完全没有异议,是把字符串“php”赋给了变量$str。但这正是“恶梦”的开始。
真正复杂、饱含细节的在于第二行代码,即:
但在开始做题之前,需要回顾一些PHP的基本知识。虽然说是基本,但我却非常惊讶很多开发同学居然对此都了解不多,或者说看过但没记住或者理解,甚至完全没去接触过。
PHP的基本类型
PHP的基本类型有哪些?或者说,通常情况下,编程语言的基本类型有哪些?
摘自PHP官方文档(链接:),基本类型有:
Boolean 布尔类型、Integer 整型、Float 浮点型、String 字符串、Array 数组、Object 对象、Resource 资源类型、NULL、Callback / Callable 类型
对PHP数组下标的理解
PHP数组,实际上是HASH的实现方式。理解这一数据结构后,再来理解它的所提供的操作就顺理成章了。PHP数组里面的知识很多,但这里只说一个点:PHP数组的下标。
先来简单看下这份额外的代码:
问:最后E字母对应的数组下标是多少?为什么?
不少同学,在回答这个问题时也卡住了。因为不知道PHP数组的下标的规则。
上面的问题回答不出来,对我们的面试题影响不大。但接下来这个问题就非常关键了:PHP数组的下标有哪些类型?如果这一点不清楚,那么会对很多PHP的函数和操作,都理解得不够透彻深刻。
其实,这些重要的信息在PHP官方文档上都有记载。但平时在学习PHP过程中,很多人都是觉得看这些“又长又臭”的文档没意思,而且花时间。此时更宁愿去网上搜索所谓的快速入门教程,但这些教程往往也是PHP开发新手编写的,他们虽然解决了问题,但很可能他们也是理解未全面,或者说明不够全面。简单来说,一切资料,都应从官网文档上寻求参考。
一如这里,PHP数组的下标类型,在PHP官方文档(链接:)已有记载。
可以用 array() 语言结构来新建一个数组。它接受任意数量用逗号分隔的
键(key) => 值(value)对。
array( key => value, ...
)
// 键(key)可是是一个整数 integer 或字符串 string
// 值(value)可以是任意类型的值
关键信息,高亮如下:
“// 键(key)可是是一个整数 integer 或字符串 string ”
也就是说,PHP数组的下标有两种类型,一种是整数,一种是字符串。
记住这一点,后面会用到这里的知识点和规则。
PHP数组与字符串的比较
下一个问题来了。PHP的数组与PHP字符串有什么不同,又有什么相同之处呢?
很多同学都知道数组与字符串的区别,但实际上它们也是有相同之处的。如果这样说,比较抽象,我们可以通过一些示例来理解。比如下面代码:
这里有一个字符串变量,它的值是(我喜欢的单元测试):PHPUnit。然后,分别输出它第0个位置、第1个位置、第10个位置的值。那么会输出什么呢?
很多语言,包括C/C++,Java等,以及PHP,字符串其实也是一个有序的序列。不同的是,不同语言底层实现方式会有差异。例如C语言中,要在字符串最后加一个结束符'\0',不然就会导致内存问题;Java语言的字符串则是缓冲区的不变值;而PHP的字符串也可以当作是一个数组的形式。例如这里的可用图表示成:
不难得知,$lib[0]会输出字符P,$lib[1]会输出字符H,最后$lib[10]的下标不存在,会出现Notice并输出空(严格来说是NULL)。
铺垫了那么多,其实是为了说明,某种情况下,PHP的字符串也可以当作数组来使用,当然与数组还是有很大区别的。
回到面试题:先看左边
回到前面的面试题。尝试解释一下第二行代码背后发生的事情。
先来做个拆解。按照PHP语言的解析机制,执行的顺序是先执行等号左边的代码,再到右边的表达式。所以,先来看等号左边部分发生了什么事情:
任何问题的处理,都离不开它的上下文。乍一看这样的代码是没问题的,但关键是:$str它不是一个字符串,而是一个数组。前面我们已经知道:
- PHP字符串也可以通过下标来操作,但实际有效下标只能是0、1、2这样的数字位置
- PHP数组下标有两种类型,可以是整数或者字符串
那么,对于一个字符串变量,给定一个字符串的下标?这意味着什么呢?PHP又是如何处理的呢?
显然,起码,这个字符串不会因此而变成一个数组。它还是一个字符串。就像质量守恒定律,一块金属,哪怕是飞上太空,到了月球,它的质量也是不变的。所以,给了一个字符串的下标,但我只允许整数下标,自然PHP语言,就像其他语言一样,会进行隐式类型转换(很多人对显式类型转换、向上、向下类型转换也不太清楚)。即:把字符串下标转成整数下标。怎么转?又是一个问题。
PHP字符串转整数的规则
PHP字符串怎么转成整数?快速问一个PHP开发人员,他都可以告诉你,可以这样做:使用intval()函数,或者前面加个(int)。那好,你继续问他,以下这些代码,结果是什么?
这时,就不一定能完全回答出来了。知道PHP的函数怎么用是一回事,知道为什么结果是这样又是一回事。理解背后的规则更为重要。
那么,PHP字符串转成整数的规则是什么呢?其实PHP官方文档(链接:)也早已记载,即:
该字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为
0(零)。合法数值由可选的正负号,后面跟着一个或多个数字(可能有小数点),再跟着可选的指数部分。指数部分由
'e' 或 'E' 后面跟着一个或多个数字构成。
简单来说,就是从前面开始,一直连续有效的部分,都会转换成整数。
再回到面试题:还是左边
对于下标name,会转换成整数,即:
结果是?根据刚学的内容,不难知道结果会是0,即字符串“name”会转化成整数0。
小结一下,到现在的情况是:
到这里,我们已经逼近真相了。我们已经知道,第二行代码,实际上是把字符串的第一个位置(下标为0)进行赋值,所以它最后不会变成数组类型。至少0下标变成了什么。可喝口水,休息一下,然后继续。
面试题的右半部分
利用代入法,第二行代码就变成了:
问题又来了,要把一个数组塞进字符串的第一个位置,会发生什么呢?
是直接只覆盖一个位置,还是后面的位置也会连带覆盖?这里不难理解,只会覆盖一个位置,即下标为0这个下标。那么对于只有一个坑位,怎么存放得了一个数组这样的庞然大物呢?
先来看下,数组又是怎么转换成字符串的。这里就不再展开细讲,因为大家已经熟悉。数组转成字符串,会变成“Array”这样的字样。即:
所以,我们的题目又简化成了:
因为只有一个坑位,可再简化成:
最后,结合上下文,应该就不能知道最终正确答案是什么了。
更完整的回答
在我看来,回答正确的答案,只能得到60分,合格线。如果能解释其中执行过程的细节解释,则可以达到80分。若能把PHP牵及的知识,进行系统的讲解,则可以达到95分。最后最后,如果能指明执行过程中发生的因隐式类型转换而发生的警告或者其他错误信息,以及在不同版本下PHP执行的差异,就更为完整了。
总而言之,这是一道基本的PHP题目,但关联的知识点非常多,考察面广。可用于评估开发同学对于PHP语言的把握程度。
文末,欢迎使用小白接口: ,免费、免开发、直接可用的云端数据接口。