2019年10月

如果在php的“二维”数组生成的时候使用IIFE unset掉,会不会变成一维?

所谓联想

受到腾讯一道面试题的启发(不确定是否为官方原题,但至少我看到的这个版本在题目的描述上就存在问题)

什么是php的多维数组类型?
A、php的值也是多种数据类型
B、php的值也是数组类型
C、php的索引值有数字和字母
D、以上都是

云运算一下

这里有一段代码,试着 运算一下?

<?php
$a = ['test'=>["test"],
    "b"=>(function (&$a){
      unset($a['test']);
      $a['c']='aaa';
})($a)];
var_dump($a);
?>

如果你的答案是

//type 1
array(2) {
  ["b"]=>
  NULL
  ["c"]=>
  string(3) 'aaa'
}
//type 2
array(1) {
  ["c"]=>
  string(3) 'aaa'
}

这两个中的一个的话,那可能你要非常小心了。因为这两个是不正确的。
正确答案

array(2) {
  ["test"]=>
  array(1) {
    [0]=>
    string(4) "test"
  }
  ["b"]=>
  NULL
}

解析

如果你没有仔细的考虑或者了解过IIFE亦或者php的语句执行的话,那你可能就会很重要中招了。
我们逐句来读这段代码

$a = ['test'=>
["test"],//生成二维数组,键是test,值是以test为值,0为键的一维数组
    "b"=>(function (&$a){ //IIFE,参数为$a的指针
      unset($a['test']); //删除$a的test
      $a['c']='aaa';//新增键c,值为aaa
})($a)];
var_dump($a);

上面已经把重要语句逐句理清楚了。咋一看没什么问题,仔细一看也没什么问题,但是问题是“答案为什么和我想的不一样”
问题在哪里呢?

答案在IIFE上

IIFE的参数是$a,可是想像一下,在执行这个函数之前,$a真的存在吗?如果不存在,那传递的这个地址(指针)就是空指针,等于新建了一个变量而已。
对,这就是答案。可是为何?
因为这一条语句并没有执行完成,也就是说,其实这里的二维数组还没有赋值给变量 $a,自然在调用这个变量的时候,就是空的了。
所以在二维数组生成的时候,用IIFE是没有办法unset掉的,这就回答了标题里面的问题。

新的风暴已经出现

那么,回到这道面试题,我新提出的问题是,“在声明一个二维数组时,二维数组的第一级键的值一定有数组”。这句话,对吗?我不知道是否有人看到这篇文章,但是答案我已经知道了。而且可以告诉你————不对。
一个IIFE所给的反例:

$a = ['test'=>'',
    "b"=>(function (){
      return ['I am fisher, 2 divs array'];
})()];
var_dump($a);

云运算一下,来碰一碰?

'0xff'==255, true or false? 略谈所谓的“2019阿里面试题”

'0xff'==255 对还是错? 再谈所谓的“2019阿里面试题”

背景

近日,php吧有吧友发布了一个所谓的2019阿里面试题。且不论真假,
里面有一道题很有意思,而且目前还没有看见一个人出来纠正这个问题。

题目如下:

$x = null;
if ('0xFF' == 255) {
    $x = (int)'0xFF'; 
}
//var_dump($x); 

问题:$x的值是多少?

他们给了这样一个“公认”的答案: $x=0而不是255。 然后后面一字一句的说得头头是道,差点让人信以为真。可静下心来,再读这段代码,仔细推敲后,发现了“完全不一样”的答案。

令人深思的十大问题之一

令人觉得可笑的是,这道号称令人值得深思的十大问题之一的问题似乎并没有多少人拿到这道题真正的去深思,甚至哪怕是动手运行一下,显然,“拿来主义”并不是一个良好的学习方式。

那么答案到底是什么呢?

答案是,此题条件不足,无解或存在特解

说人话就是,在不同的php版本下,这段代码有着不同答案

答案

在php7+环境下,$x 的值为null. 对,这是一个你最不可能相信的答案。

在php5.6-环境下,$x的值为0.

寻找根源

这是一个非常奇怪的答案,不应该会出现这种情况,除非是刻意而为之。
一个很容易想到的关键,应该是'0xFF' == 255这里出现问题。

字符串与数字进行比较,根据C语言的类型转换运算,低类型应该向高类型进行隐式转换。所以这里字符串要转为int类型。明显根据经验,php会使用is_numeric进行转换,看来,问题的根源就在于此了。

证明猜测

为了证明猜测的正确性,我们可以用以下语句来检验。

$x = null;
if ('0xff' == 255) {
    $x = (int)'0xFF'; 
}
var_dump('0xff'+0); 
var_dump(is_numeric('0xff'));
var_dump((int)'0xff');
var_dump('0xff' == 255); 
语句php7.xphp5.x对比
'0xff'+0int(0)int(255)出现差异
is_numeric('0xff')bool(false)bool(true)出现差异
(int)'0xff'int(0)int(0)正常
'0xff' == 255bool(false)bool(true)出现差异

语句解释:

'0xff'+0 : 强制类型转换且不改变数值,非常常见的一种数值化字符串方法。

is_numeric('0xff'):判别字符串形式下的十六进制,php5.x与7.x相差较大,见后文说明。

(int)'0xff':使用int强制转换,从左到右读取数字,遇到非数字结束。

'0xff' == 255):对比结果。

很明显,结果出来了。确实是is_numeric出现了问题。
事实上,官网手册上也验证了我的猜测。

PHP 7.0.0+ Strings in hexadecimal (e.g. 0xf4c3b00c) notation are no longer regarded as numeric strings, i.e. is_numeric() returns FALSE now.

如此,为何

为何要更改对字符串形式的16进制的解析呢?这个问题说来也简单。因为is_numeric并不是一个安全的函数,解析字符串形式的16进制很可能引起sql注入的安全问题,这里不过多讨论,想了解更多的请百度相关文章。所以在php7+,is_numeric不再解析字符串形式的16进制,是为了更加的安全。不论这道题是否是所谓的“2019阿里面试题”,希望所有还在这条路上摸索的人,都要去质疑这种网上流传已久的“神”题。我更加希望这不是阿里的面试题,因为如果HR不加思索的从网上“拿”这个题目出来让这些phper去做,甚至连技术负责人把关都没把到,那可能又是一番笑话了。所以,环境才是最重要的,代码离开了环境,谁能保证永远坚持不懈的动下去。共勉