php 5.6 与之前版本不兼容中的数组属性定义辨析

WBOY
发布: 2016-06-23 13:28:07
原创
1082 人浏览过

在php5.6官方文档的不兼容页(http://php.net/manual/zh/migration56.incompatible.php)中提到了几个与以前版本不兼容的情况,其中提到了为类定义数组属性时,不兼容的情况,原文及示例如下:

在 PHP 5.6 之前的版本中,为类定义数组类型的属性时, 如果数组中同时使用了显式数组键和隐式数组键,并且显式的键和隐式的序列键相同, 那么数组的键将被覆盖。例如:

 1 <?php 2 class C { 3     const ONE = 1; 4     public $array = [ 5         self::ONE => 'foo', 6         'bar', 7         'quux', 8     ]; 9 }10 11 var_dump((new C)->array);12 ?>
登录后复制

以上示例在PHP 5.5中输出:

1 array(2) {2   [0]=>3   string(3) "bar"4   [1]=>5   string(4) "quux"6 }
登录后复制

在PHP 5.6中输出:

array(3) {  [1]=>  string(3) "foo"  [2]=>  string(3) "bar"  [3]=>  string(4) "quux"}
登录后复制

以上的例子,其实是非常特例的情况,其出现的前提条件有几条:

1. 必须是为类定义数组属性,并且是在类变量定义时初始化该属性的情况;

2. 一定是显式数组键在前,隐式数组键在后,隐式数组键对与自身位置相同的显示数组键的值的覆盖的情况;如果隐式数组键在前,显式数组键定义在后,则覆盖是一定会发生的,与版本无关;

3. 显式数组键必须是常量(包括类常量)方式,如果是字面量常量,则无论什么版本,在以上情况下,都不会出现隐式数组键覆盖显式数组键;

考察以下示例在PHP 5.5中的输出:

1.1 非类数组成员定义:

1 $array = [2 ONE=>'foo',3  'bar',4  'quux'5 ];6 var_dump($array);
登录后复制

输出:

array(3) {  [1] =>  string(3) "foo"  [2] =>  string(3) "bar"  [3] =>  string(4) "quux"}
登录后复制
登录后复制
登录后复制

1.2 非初始化时赋值:

1 define('ONE', 1);2 class C {3 public $array;4 }5 $c = new C;6 $c->array = [ONE=>'foo','bar','quux'];7 var_dump($c->array);
登录后复制

输出:

array(3) {  [1] =>  string(3) "foo"  [2] =>  string(3) "bar"  [3] =>  string(4) "quux"}
登录后复制
登录后复制
登录后复制

 1 define('ONE', 1); 2 class C { 3 const ONE = 1; 4  public $array; 5  public function __construct() { 6 $this->array = array( 7 'bar', 8  ONE => 'foo', 9  'quux',10  );11  }12 }13 $c = new C;14 var_dump($c->array);
登录后复制

输出:

array(3) {  [0] =>  string(3) "bar"  [1] =>  string(3) "foo"  [2] =>  string(4) "quux"}
登录后复制

2. 显式键对隐式键的覆盖:

 1 define('ONE', 1); 2 class C { 3 const ONE = 1; 4  public $array = array( 5 'bar', 6  'quux', 7  ONE => 'foo', 8  'guru' 9  );10 }11 $c = new C;12 var_dump((new C)->array);
登录后复制

输出:

array(3) {  [0] =>  string(3) "bar"  [1] =>  string(3) "foo"  [2] =>  string(4) "guru"}
登录后复制
登录后复制

3. 字面量常量作为显式键名:

 1 class C { 2 public $array = array( 3 'bar', 4  'quux', 5  1 => 'foo', 6  'guru' 7  ); 8 } 9 $c = new C;10 var_dump((new C)->array);
登录后复制

输出:

array(3) {  [0] =>  string(3) "bar"  [1] =>  string(3) "foo"  [2] =>  string(4) "guru"}
登录后复制
登录后复制

1 class C {2 public $array = array(3 1 => 'foo',4  'bar',5  'quux',6  );7 }8 $c = new C;9 var_dump((new C)->array);
登录后复制

输出:

array(3) {  [1] =>  string(3) "foo"  [2] =>  string(3) "bar"  [3] =>  string(4) "quux"}
登录后复制
登录后复制
登录后复制

其实本质上,这是一个隐藏的很深的小bug。

在数组的定义中,如果有部分单元指定了数字键名,其后的隐式键名会延续此前最大数字(包括隐式或显式)键名,而不应产生隐式键名覆盖显式数字键名情况,无论显式键名是字面量常量还是符号常量。

见官方手册数组一节:http://php.net/manual/zh/language.types.array.php:

1 <?php2 $array = array(3          "a",4          "b",5     6 => "c",6          "d",7 );8 var_dump($array);9 ?>
登录后复制

以上例程会输出:

array(4) {  [0]=>  string(1) "a"  [1]=>  string(1) "b"  [6]=>  string(1) "c"  [7]=>  string(1) "d"}
登录后复制

只不过,5.6之前的版本在实现为类初始化数组成员时,用符号常量作数字键,对部分单元进行命名,出现了与数组语义定义不符的情况。

鉴于此种情况极其少见,故其影响较小,但一旦出现,则由此引起的bug极其难查。

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!