02-看官方文档学PHP基础-Arrays

PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型在很多方面做了优化,因此可以把它当成真正的数组,或列表(向量),散列表(是映射的一种实现),字典,集合,栈,队列以及更多可能性。由于数组元素的值也可以是另一个数组,树形结构和多维数组也是允许的。

语法

定义数组 array()

array(  key =>  value
, ...
)

// 键(key)可以是一个整数 integer 或字符串 string
// 值(value)可以是任意类型的值
  1. 最后一个数组单元之后的逗号可以省略。如:array(1, 2)
  2. 对多行数组定义通常保留最后一个逗号,这样要添加一个新单元时更方便。
  3. 自 5.4 起可以使用短数组定义语法,用 [] 替代 array()

Example #1 一个简单数组

<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
);

// 自 PHP 5.4 起
$array = [
"foo" => "bar",
"bar" => "foo",
];
?>

key 会有如下的强制转换:

  1. 包含有合法整型值的字符串会被转换为整型。 例如键名 “8” 实际会被储存为 8。但是 “08” 则不会强制转换,因为其不是一个合法的十进制数值。
  2. 浮点数也会被转换为整型,意味着其小数部分会被舍去。 例如键名 8.7 实际会被储存为 8。
  3. 布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。
  4. Null 会被转换为空字符串,即键名 null 实际会被储存为 “”。
  5. 数组和对象不能被用为键名。坚持这么做会导致警告:Illegal offset type。

对同一键名赋值,后面的值会覆盖之前的赋值

Example #2 类型强制与覆盖示例

<?php
$array = array(
1 => "a", // 键值是1
"1" => "b", // 键值转换成1
1.5 => "c", // 键值转换成1
true => "d", // 键值转换成1
);
var_dump($array);
//输出
//array(1){
[1]=>string(1)"d"
}
?>
  1. PHP 数组可以同时含有 integerstring 类型的键名,因为 PHP 实际并不区分索引数组和关联数组。
  2. 如果对给出的值没有指定键名,则取当前最大的整数索引值,而新的键名将是该值加一。如果指定的键名已经有了值,则该值会被覆盖。

Example #3 混合 integer 和 string 键名

<?php
$array = array(
"foo" => "bar", // key: "foo", value: "bar"
"bar" => "foo", // key: "bar", value: "foo"
100 => -100, // key: 100, value: -100
-100 => 100, // key: -100, value: 100
);
var_dump($array);
?>

key 为可选项。如果未指定,PHP 将自动使用之前用过的最大 integer 键名加上 1 作为新的键名。

Example #4 没有键名的索引数组

<?php
$array = array("foo", "bar", "hallo", "world"); // array([0]=>"foo", [1]=>"bar", [2]=>"hallo", [3]=>"world")
var_dump($array);
?>

Example #5 仅对部分单元指定键名

<?php
$array = array(
"a", // [0]=>"a"
"b", // [1]=>"b"
6 => "c", // [6]=>"c"
"d", // [7]=>"d"
);
var_dump($array);
?>

用方括号语法访问数组单元

数组单元可以通过 array[key] 语法来访问。

Example #6 访问数组单元

<?php
$array = array(
"foo" => "bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);

var_dump($array["foo"]); // ["foo"]=>"bar"
var_dump($array[42]); // [42]=>24
var_dump($array["multi"]["dimensional"]["array"]); // ["array"]=>"foo"
?>

方括号和花括号可以互换使用来访问数组单元(例如 $array[42]$array{42} 在上例中效果相同)。

自 PHP 5.4 起可以用数组间接引用函数或方法调用的结果(如:getArray()[1];)。之前只能通过一个临时变量(如:用$tmp来存放数组,然后$tmp[1];)。

自 PHP 5.5 起可以用数组间接引用一个数组原型。

Example #7 数组间接引用

<?php
function getArray() {
return array(1, 2, 3);
}

// on PHP 5.4
$secondElement = getArray()[1];

// previously
$tmp = getArray();
$secondElement = $tmp[1];

// or
list(, $secondElement) = getArray();
?>

试图访问一个未定义的数组键名与访问任何未定义变量一样:会导致 E_NOTICE 级别错误信息,其结果为 NULL。

用方括号的语法新建/修改

$arr[key] = value; //给数组赋值
$arr[] = value;
// key 可以是 integer 或 string
// value 可以是任意类型的值

如果 $arr 还不存在,将会新建一个,这也是另一种新建数组的方法。(不鼓励)

初始化变量的最好方式是直接给其赋值。

要删除某键值对,对其调用 unset() 函数。

<?php
$arr = array(5 => 1, 12 => 2);

//如果给出方括号但没有指定键名,则取当前最大整数索引值,新的键名将是该值加上 1(但是最小为 0)。
//如果当前还没有整数索引,则键名将为 0。 $arr[] = 56; 实际是给键值13的索引赋值
$arr[] = 56; // This is the same as $arr[13] = 56;
// at this point of the script

$arr["x"] = 42; // This adds a new element to
// the array with key "x"

unset($arr[5]); // This removes the element from the array

unset($arr); // This deletes the whole array
?>

注意这里所使用的最大整数键名不一定当前就在数组中。它只要在上次数组重新生成索引后曾经存在过就行了。以下面的例子来说明:

<?php
// 创建一个简单的数组
$array = array(1, 2, 3, 4, 5);
// print_r($array);

// 现在删除其中的所有元素,但保持数组本身不变:
foreach ($array as $key => $value) {
unset($array[$key]);
}
// print_r($array);

// 添加一个单元(注意新的键名是 5,而不是你可能以为的 0)
$array[] = 6; //之前删除了$array的元素,但是其本身并没有变
print_r($array); //Array ( [5] => 6 )

// 重新索引:
$array = array_values($array);
$array[] = 7;
print_r

实用函数

更多函数:http://php.net/manual/zh/ref.array.php

foreach 控制结构是专门用于数组的。它提供了一个简单的方法来遍历数组。

unset()可以删除数组中的某个键,但删除后不会重建索引,可以用array_values()重建索引

<?php
$a = array(1 => 'one', 2 => 'two', 3 => 'three');
unset($a[2]);
/* will produce an array that would have been defined as
$a = array(1 => 'one', 3 => 'three');
and NOT
$a = array(1 => 'one', 2 =>'three');
*/

$b = array_values($a);
// Now $b is array(0 => 'one', 1 =>'three')
?>

数组,有所为有所不为 (Array do’s and don’ts)

Why is $foo[bar] wrong?

这样是错的,但可以正常运行。Why?????? 因为PHP自动将其转换为字符串了.

PHP 自动将裸字符串(没有引号的字符串且不对应于任何已知符号)转换成一个其值为该裸字符串的正常字符串。

This does not mean to always quote the key. Do not quote keys which are constants or variables, as this will prevent PHP from interpreting them.

综合例子:

着重注意 到这几行:

define('fruit', 'veggie');
print "Hello $arr[fruit]"; // Hello apple,这里的fruit被当成字符串对待了
print "Hello {$arr[fruit]}"; // Hello carrot,这里的fruit被当成变量对待

完整例子:

<?php
// Show all errors
error_reporting(E_ALL);

$arr = array('fruit' => 'apple', 'veggie' => 'carrot');

// Correct
print $arr['fruit']; // apple
print $arr['veggie']; // carrot

// Incorrect. This works but also throws a PHP error of level E_NOTICE because
// of an undefined constant named fruit
//
// Notice: Use of undefined constant fruit - assumed 'fruit' in...
print $arr[fruit]; // apple

// This defines a constant to demonstrate what's going on. The value 'veggie'
// is assigned to a constant named fruit.
define('fruit', 'veggie');

// Notice the difference now
print $arr['fruit']; // apple
print $arr[fruit]; // carrot

// The following is okay, as it's inside a string. Constants are not looked for
// within strings, so no E_NOTICE occurs here
print "Hello $arr[fruit]"; // Hello apple,这里的fruit被当成字符串对待了

// With one exception: braces surrounding arrays within strings allows constants
// to be interpreted
print "Hello {$arr[fruit]}"; // Hello carrot,这里的fruit被当成变量对待
print "Hello {$arr['fruit']}"; // Hello apple

// This will not work, and will result in a parse error, such as:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// This of course applies to using superglobals in strings as well
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";

// Concatenation is another option
print "Hello " . $arr['fruit']; // Hello apple
?>

[]之间必须有一个表达式。这意味着可以这样写(用函数返回值作为数组索引的例子):

<?php
echo $arr[somefunc($bar)];
?>

一些可用的已知常量:

<?php
$error_descriptions[E_ERROR] = "A fatal error has occured";
$error_descriptions[E_WARNING] = "PHP issued a warning";
$error_descriptions[E_NOTICE] = "This is just an informal notice";
?>

E_ERROR是一个有效的标识符,上面的代码等价于下面这段,因为 E_ERROR等于1:

<?php
$error_descriptions[1] = "A fatal error has occured";
$error_descriptions[2] = "PHP issued a warning";
$error_descriptions[8] = "This is just an informal notice";
?>

那么为什么这样做不好?(So why is it bad then?)\

强烈建议不要使用 $foo[bar] 这样的写法,而要使用 $foo['bar'] 来访问数组中元素。在双引号字符串中,不给索引加上引号是合法的因此 $foo[bar] 是合法的,在实际测试中,这么做确实可以访问数组的该元素,但是会报一个常量未定义的 notice。

转换为数组

将任意类型的一个值转为数组,将得到一个只有一个元素下标是0的数组,该值就是这个数组唯一的键值,(array)$scalarValuearray($scalarValue) 完全一样。

如果一个 object 类型转换为 array,则转换成的这个数组,数组的元素是object的属性,数组的key是object所属类的成员变量名

这里要注意几个例外

  1. integer类型的属性是不可访问的
  2. private 变量前会加上类名作为前缀
  3. protected 变量前会加上*做前缀
  4. 将 NULL 转换为 array 会得到一个空的数组
    这些前缀的前后都各有一个 NULL 字符。这会导致一些不可预知的行为:
<?php
class A {
// 转换为array后,`private` 变量前会加上类名作为前缀,键值表现应为`[AA]=>1`
private $A=1; // This will become '\0A\0A'
}

class B extends A {
// 转换为array后,`private` 变量前会加上类名作为前缀,键值表现应为`[BA]=>2`
private $A=2; // This will become '\0B\0A'
// 毫无疑问的`[AA]=>3`
public $AA=3; // This will become 'AA'
}

// 输出结果是`array(3) { ["BA"]=> int(2) ["AA"]=> int(3) ["AA"]=> int(1) }`
var_dump((array) new B());
?>

比较

可以用 array_diff()数组运算符来比较数组。

示例


<?php
// This:
$a = array( 'color' => 'red',
'taste' => 'sweet',
'shape' => 'round',
'name' => 'apple',
4 // key will be 0
);

$b = array('a', 'b', 'c');

// . . .is completely equivalent with this:
$a = array();
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name'] = 'apple';
$a[] = 4; // key will be 0

$b = array();
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';

// After the above code is executed, $a will be the array
// array('color' => 'red', 'taste' => 'sweet', 'shape' => 'round',
// 'name' => 'apple', 0 => 4), and $b will be the array
// array(0 => 'a', 1 => 'b', 2 => 'c'), or simply array('a', 'b', 'c').
?>

PHP 5 起可以通过引用传递来做到: 直接改变数组的值

<?php
$colors = array('red', 'yellow', 'green', 'gray', 'black', 'white', 'blue');

// PHP5 霸道的直接改变数组的值
foreach ($colors as &$color) {
$color = strtoupper($color);
// echo "Do you like " . $color . "?". PHP_EOL;
}

// 老版本的间接办法
// Workaround for older versions
foreach ($colors as $key => $color) {
$colors[$key] = strtoupper($color);
}
unset($color); //没搞懂这句的必要性
print_r($colors);
?>
<?php
// fill an array with all items from a directory
$handle = opendir('.');
// `while ($file = readdir($handle)) {`这样也是可以的,为什么要写的那么复杂?
while (false !== ($file = readdir($handle))) {
$files[] = $file;
}
closedir($handle);
sort($files); //排序
var_dump($files);
?>

递归和多维数组

<?php
$fruits = array ( "fruits" => array ( "a" => "orange",
"b" => "banana",
"c" => "apple"
),
"numbers" => array ( 1,
2,
3,
4,
5,
6
),
"holes" => array ( "first",
5 => "second",
"third"
)
);

// Some examples to address values in the array above
echo $fruits["holes"][5]; // prints "second"
echo $fruits["fruits"]["a"]; // prints "orange"
unset($fruits["holes"][0]); // remove "first"

// Create a new multi-dimensional array
$juices["apple"]["green"] = "good";
?>

值的拷贝:使用引用运算符通过引用来拷贝数组。

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;

$arr2[] = 4; // $arr2 is changed to (2,3,4)
// $arr1 is still array(2, 3)
// var_dump($arr2);
$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same to (2,3,4)
var_dump($arr3); //array(3) { [0]=> int(2) [1]=> int(3) [2]=> int(4) }
?>
<?php
$a['a'] = null;
$a['b'] = array();

var_dump($a['a']["non-existent"]); // DOES NOT throw an E_NOTICE error as expected.

// Undefined index: non-existent
var_dump($a['b']['non-existent']); // throws an E_NOTICE as expected
?>