PHP 数组
什么是数组?
一个变量一般只能存一个值,而数组是一个变量里面可以存多个值。
首先PHP里面有八种数据类型,其中数组Array是非常重要的一种数据类型(一个项目中使用数组占30%)
第一: 把若干变量,按有序的形式,组织起来的一种形式,这些数据元素的集合称为数组
第二: 数组按下标个数分有两类,
1). 一维数组,
2). 二维数组等,二维以上的数组通常称"多维数组"
第三:数组是一个容器,使用的目的是可以批量操作
解释一
在别的语言里一般这样定义数组,把相关类型的若干变量,按有序的形式组织在一起,
而PHP中数组的确切概念应该是,把若干个变量组织在一起,不分相关的元素,也不分有没有序,所以PHP数组是特别灵活的数组,这也是PHP的一个特点。
使用数组的目的就是为了批量操作,通常把相关的数据放到一个组里面,我们只要对这个组操作,就对所有组中的成员操作了,这是使用数组最主要的目的。
在PHP中有按照下标不同分两种数组,索引数组 和 关联数组
索引(indexed):数组的索引值是整数,以0开始(但不一定是连续的)
关联(associative):数组以"字符串作为索引值",关联数组更像操作表。索引值为列名,用于访问列的数据。
解释二
在别的一些语言里面,数组都是有序的,数组里面必须是键 => 值映射,数组下标只有一种类型,就是索引数组(数组下标是0,1,2,3…),而PHP数组是多样的,声明也有多种方式
比如,下标可以是数字0对应的值,也可以是字符串对应的值
$arr = array('one', 10, 13, 4, true);
整数是下标的是"索引数组",字符串是下标是叫"关联数组"
$arr[0] = 'a'; // 索引数组 $arr['one'] = 'b'; // 关联数组
PS:
PHP中的数组实际上是一个有序的图,图是一种把values映射到keys的类型,
此类型在很多方面做了优化,因此可以把他当成真正的数组来使用,或列表(矢量),散列表(是图的一种实现),字典,集合,栈,队列以及更多可能性。因为可以用另一个PHP数组作为值,也可以很容易的模拟树。
解释三
别的语言数组的定义,比如C语言或java的数组,是相关类型的,有序的,多个元素的集合。
比如C语言 int a[10] = 这个声明体现了两个信息
第一个信息类型,数组里面只能存整数,浮点数、布尔型都存不了
第二个信息a[10]中括号里面10,里面必须存10个,多一个少一个都不行
别的一些语言里,数组有两个限制,一个是类型限制必须是相关类型,第二个是长度的限制。所以别一些语言要想实现类型不限、长度不限制,经常做一些容器
PS:
比如,C语言里面经常做列表,单线列表,双线列表……堆、栈
JAVA里面经常做集合、图、树、堆、栈……
所以在C语言里面,要想学数据结构,什么堆、栈、列表,有可能要花一周的时间
如果在JAVA里面学那些集合,也要将近一周的时间,才能学明白,然后用起来还不太灵活。
而PHP的数组,那些数据结构(数据结构容器)要学的东西,PHP数组全部搞定,
所以在PHP里面不用学堆、栈、图、列表、数……这些都不用学,就可以编程,所以PHP数组在项目中的应用占到30%,而别的一些语言里面,数组,还有那些容器,加在一起才应用到30%,
而且PHP数组非常好理解,使用还容易
PHP数组的特点:
1). 长度没有限制(数据别超过服务器限制的最大内存,不然会内容溢出)
2). 类型没有限制(篮子里装水果也行,装矿泉水也行)
数组特性(PHP数组的一些特征)
1、一个数组中存的是多个内容,数组中的内容叫作"元素"
2、每个元素都是由"键 和 值"两部分组成的(别的语言里可能叫哈希)
3、通过键(key)下标来使用值,下标分两种类型,
1). 整数(索引数组)
2). 字符串(关联数组)
4、使用[]中括号操作下标,也可以使用花括号{},建议使用[]中括号来指定下标
5、在使用下标时候,如果是关联数组,一定要使用引号(单引号,双引号都行),不要使用常量名称
6、数组的下标是自动增长的,默认是从0开始的,自动增长的都是出现过的最大值加 1
7、关联数组的字符串下标,不会影响索引下标的排列规则
8、使用array()函数声明数组,默认是索引的下标,是从0开始的
9、array()函数声明数组,使用"=>"符号指定下标(PHP5.4以后,可以像其它语言一样声明数组了)
10、删除数组中的一个元素,使用的是unset(),数组下标不会重新索引,需要使用array_value()函数重新索引
PHP中的数组声明有多种方式,PHP数组的应用是非常灵活的,创建数组也是非常灵活的,
当然除了我们自己创建的数组,后期程序的应用也会自动生成一些数组,比如链接msysql数据库,返回数据表里面存的内容的数组。
一、数组的定义(声明)
1、直接赋值声明数组
2、使用array()语言结构声明数组
3、PHP5.4版本新的中括号声明方式 []
4、多维数组的声明
特征
1、一个数组中存的是多个内容,数组中的内容叫作"元素"
2、每个元素都是由"键 和 值"两部分组成的(别的语言里可能叫哈希)
键(key)和值(value)是一种映射关系,键(key)也叫下标。变量$arr是数组类型,里面有两个元素,第二个元素的键(下标)是['two'],值是"222"
$arr = array("one"=>"111", "two"=>"222"); $arr['two']; // 222
PHP声明数组从语法上来说,在早期PHP2.0版本里面支持两种方式,
1). 一种是直接赋值声明
2). 一种是使用array()函数声明
3). 还有一种是PHP5.4以后新增的 [] 声明方法
特性
3、通过键(key)下标来使用值。下标分两种类型,1). 整数(索引数组),2). 字符串(关联数组)
1、直接赋值声明数组
索引数组
$arr[0] = 1; $arr[1] = 2; $arr[2] = 3; print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 )
关联数组
$arr['one'] = 1; $arr['two'] = 2; $arr['three'] = 3; print_r($arr); // Array ( [one] => 1 [two] => 2 [three] => 3 )
总结:
直接赋值声明数组,就是直接使用中括号,在一个变量里面开辟出多个下标,下标可以无限的加下去没有长度的限制。
索引数组 和 关联数组的区别很明显,就是下标是整数还是字符串。
二、数组的下标
特征
4、使用[]中括号操作下标,也可以使用花括号{},建议使用[]中括号来指定下标
用中括号来操作
$arr['one'] = 1; $arr['two'] = 2; $arr['three'] = 3; echo $arr['one'],'<br/>'; // 1 echo $arr{'three'}; // 3
用花括号下标访问数组,数组声明也能用花括号
$arr{'one'} = 1; $arr['two'] = 2; $arr['three'] = 3; echo $arr{'one'}; // 1
实际使用中不建议用花括号{},用的人非常少,因为其它语言都是用中括号
注意一点:
字符串中嵌套变量时,用花括号断开,意思是当做特殊符号把变量隔出来,
但是数组的中括号不算特殊符号(很多人以为[]是特殊符号,其实不是特殊符号),中括号放到数组里面,是"数组变量名"的一部分,
所以字符串在解析的时候,遇到中括号[]不算是特殊字符,不会把变量断开
下面数字 123 被嵌入到字符串中
$arr['one'] = '123'; echo "I am not$arr[one]available"; // I am not123available
字符串中数组下标用花括号,在解析字符串的时候不算是特殊符号
$arr['one'] = '123'; echo "I am not$arr{one}available"; // I am notArray{one}available
输出的字符串,不解析变量,而且还报注意:Notice: Array to string conversion in……
建议使用中括号[],不建议使用花括号{}
特征
5、在使用下标时候,如果是关联数组,一定要使用引号(单引号,双引号都行),不要使用常量名称
使用关联数组的时候,下标是字符串形式,字符串必须用双引号或单引号引起了,推荐用单引号,因为效率比双引号高
$arr[four] = 4; echo $arr[four]; // 4 /** * 1.如果不加单引号或双引号,里面的four按照常量解析, * 2.没有声明常量的情况下,常量名four会转成字符串 * 3.这样虽然能打印出值4,但是系统会报注意/警号信息,虽然不是报错信息,但是效率会很低 * 因为系统检查常量不存在的情况下,会转成字符串,这个效率会比直接使用字符串慢 * * PHP7版本中系统报错Warning信息 * Warning: Use of undefined constant four - assumed 'four' (this will throw an Error in a future version of PHP) in …… */
这个细节也是应该注意的,用关联数组的时候,下标是字符串,就要用引号印起来,这个细节点很重要
数组的"索引下标"和"关联下标",是可以同时存在的,但是也不建议这样用
但是通过PHP系统函数返回的数组,一般都返回这两种在一起的形式,凭我们的喜好选择索引下标或关联下标
$arr[0] = 1; $arr[1] = 2; $arr[2] = 3; $arr{'one'} = 1; $arr['two'] = 2; $arr['three'] = 3; print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 [one] => 1 [two] => 2 [three] => 3 )
PHP索引和关联数组需要注意的细节
1、包含有合法整型的字符串会被转换为整型
例如:键名是字符串的"2",实际会被存为为2。但是字符串"02"不会强制转换,因为其不是一个合法的十进制数值
2、浮点数也会被转换为整数,但是其小数部分会被舍去。例如:键名2.7,实际会被储存为2
3、布尔值做下标也会被转换成整形。既,键名true实际被存储为1,而键名false会被存储为0。
4、Null会被转换为空字符串。既,键名Null实际会被存储为空字符串""
5、数组和对象不能做键名的。坚持这么做会导致警告:llegal offset type
6、如果在数组定义多个单元都使用了同一个键名,则只有使用了最后一个,之前的都被覆盖了。
7、如果对给出的值没有指定键名,则取当前最大整数索引值,而新的键名将是该值加一。
如果指定的建名已经有值,则该值会被覆盖。
3、key的强制转换
数组的下标就是"整形"和"字符串"两种,但是变量有八中类型,PHP又是弱类型语言,弱类型语言意味着其它类型作为下标也没问题。
是没有问题,但是PHP数组下标只支持整数和字符串这两种,其它的会被自动强制转换
细节1:包含有,合法整型的字符串,会被转换为整型
例如:字符串的下标"2"会被存为整形2
$arr[0] = 1; $arr[1] = 2; $arr["2"] = 3; // 字符串"2"做下标,打印结果下标还是2 print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 )
但是字符串"02"不会强制转换,因为其不是一个合法的十进制数值,"02"是八进制的数
$arr[0] = 1; $arr[1] = 2; $arr["02"] = 3; // 字符串"02"不会强制转换,因为其不是一个合法的十进制数值,"02"是八进制的数 print_r($arr); // Array ( [0] => 1 [1] => 2 [02] => 3 )
这个细节面试时可能会提到
细节2:浮点数也会被转换为整数,但是其小数部分会被舍去。例如:键名2.7,实际会被储存为2
PHP好些地方强制类型转换都是割舍的,key: 2.7 实际会被储存为2
$arr[0] = 1; $arr[1] = 2; $arr[2.7] = 3; // 键名2.7实际会被储存为2 print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 )
细节3:布尔值做下标也会被转换成整形。既,键名true实际被存储为1,而键名false会被存储为0。
$arr[0] = 1; $arr[1] = 2; $arr[2] = 3; $arr[true] = 'true覆盖'; // true会转换成1,会把上面的$arr[1]=2给覆盖了 $arr[false] = 'false覆盖'; // false会被转换成0,把上面的$arr[0]=>1给覆盖了 print_r($arr); // Array ( [0] => false覆盖 [1] => true覆盖 [2] => 3 )
细节4:Null会被转换为空字符串。既,键名Null实际会被存储为空字符串""
总结:
索引可以用中括号,或花括号,建议用中括号
索引数组和关联数组是可以在一起用的
常量名称,别作为数组下标,可以做但是会有效率的影响
各种变量类型都可以做数组下标,但是会强制转换成,索引数组和关联数组
继续讨论,继续讨论数组声明的细节问题
细节6:如果在数组定义多个单元都使用了同一个键名,则只有使用了最后一个,之前的都被覆盖了
这种情况就像是,前面出现了一变量$a,后面又给变量$a重新赋值,是一个重新覆盖的问题
虽然这个问题很小但很重要,操作的是同一个元素,所以第二个元素给第一个元素重新赋值了
$arr[0] = 10; $arr[0] = 30; // 后面又出现一个下标为10的单元 print_r($arr); // Array ( [0] => 30 )
如果声明数组的时候,下标可以不连续吗?
如果是其它一些语言这是不行的,其它语言只有索引数组,而且下标必须连续的
PHP里的数组下标可以不用整数,可以用字符串,另外是整数下标还可以不连续
$arr[0] = 10; $arr[100] = 30; print_r($arr); // Array ( [0] => 10 [100] => 30 )
特征6:数组的下标是自动增长的,默认是从0开始的,自动增长的都是出现过的最大值加一
如果不指定下标,下标会逐一的自动增加
$arr[] = 'one'; $arr[] = 'two'; $arr[] = 'three'; $arr[] = 'four'; $arr[] = 'five'; $arr[] = 'six'; $arr[] = 'seven'; $arr[] = 'eight'; $arr[] = 'nine'; $arr[] = 'ten'; print_r($arr); // Array ( [0] => one [1] => two [2] => three [3] => four [4] => five [5] => six [6] => seven [7] => eight [8] => nine [9] => ten )
通常写一个循环向数组里添加很多东西
$arr = array(); // 声明一个数组(不声明也行) for($i = 0; $i < 100; $i++){ $arr[] = $i * $i; } print_r($arr); // Array ( [0] => 0 [1] => 1 [2] => 4 [3] => 9……) // 建一个空容器,再循环往容器里装很多个值,就用这个办法
如果下面这样,突然中间有一个下标8出现,下标会在最大值8上加1
$arr[] = 1; $arr[] = 2; $arr[] = 3; $arr[8] = 4; // 突然有一个下标8出现 $arr[] = 5; $arr[] = 6; $arr[] = 7; $arr[] = 8; $arr[] = 9; print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 5 [10] => 6 [11] => 7 [12] => 8 [13] => 9 ) /*** 下标是从0开始的(国外的楼一层是标的是0层),下标会在最大值8上加1,而是从9,10,11……继续往后排 Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 5 [10] => 6 [11] => 7 [12] => 8 [13] => 9 ) ***/
下标默认从0开始,后面出现前面一样的下标,就把前面的值覆盖,如果不出现一样的下标就自动用最大下标值加一
$arr[] = 1; $arr[] = 2; $arr[] = 3; $arr[8] = 4; // 1. 指定了下标8 $arr[] = 5; // 2. 上面指定了下标8 这里的下标是9 $arr[9] = 6; // 3. 这里下标还是9,会把上面($arr[] = 5;)覆盖掉 $arr[] = 7; $arr[4] = 8; // 这块在出现一个4的下标,4后面的下标是11,不会补齐之前空缺的键 $arr[] = 9; print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 6 [10] => 7 [4] => 8 [11] => 9 ) /*** Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 6 [10] => 7 [4] => 8 [11] => 9 ) ****/
特征7:关联数组的字符串下标,不会影响索引下标的排列规则
$arr[] = 1; $arr[] = 2; $arr[] = 3; $arr[8] = 4; $arr[] = 5; $arr[9] = 6; $arr[] = 7; $arr[4] = 8; $arr[] = 9; $arr['ten'] = 10; // 这里出现一个字符串下标 $arr[] = 11; // 问这个下标是多少?是12 print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 6 [10] => 7 [4] => 8 [11] => 9 [ten] => 10 [12] => 11 ) /*** Array ( [0] => 1 [1] => 2 [2] => 3 [8] => 4 [9] => 6 [10] => 7 [4] => 8 [11] => 9 [ten] => 10 [12] => 11 ) ***/
索引下标是整形,除了非法字符(八进制、十六进制)不能做下标,整形有正负数,如果用负数做下标会怎么样呢?
1). 负数是可以做下标的,只是平时习惯了用正数做下标从0开始增长,但是PHP是支持负数的
2). 但是自动增长的都是出现过的最大值加一,负数不是最大值
-100是最小值,后面自动增长的索引,不会受到-100影响
$arr[] = 1; $arr[] = 2; $arr[] = 3; $arr[] = 4; $arr[] = 5; $arr[-100] = -6; // 这里出现负-100,后面的下标是怎么自增长 $arr[] = 7; $arr[] = 8; $arr[] = 9; print_r($arr); // Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [-100] => -6 [5] => 7 [6] => 8 [7] => 9 ) /*** Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [-100] => -6 [5] => 7 [6] => 8 [7] => 9 ) ***/
索引下标自动增长的一些问题,面试题出的比较多。
4、array()声明数组
PHP声明数组有多种方法,array()函数声明数组也是非常常用的
说array()是一个函数,其实并非是一个真正的函数,跟include、echo一样相当一个系统指令
比如用function_exists()判断array函数是否存在,判断结果是"不存在",但是手册上确实有array()函数,像这样的函数还有。
if(function_exists("array")){ echo '存在'; }else{ echo '不存在'; // 不存在 }
PS:
key可以是integer或者string,value可以是任意类型
应该始终在用字符串表示的数组索引上加引号,例如$foo['far']而不是$foo[bar]
特征8:使用array()函数声明数组,默认是索引的下标,而且是从0开始的
默认是索引的下标,都是是从0开始的
$arr = array('one', 'two', 'three', 'four'); print_r($arr); // Array ( [0] => one [1] => two [2] => three [3] => four )
特征9:array()函数声明数组,使用"=>"符号指定下标(PHP5.4以后,可以像其它语言一样声明数组了)
array()声明数组
1). 下标还是有索引下标 和 字符串下标两种
2). 自动增长的下标,默认从0开始
3). 如果出现同一个键名,后面出现的覆盖前面的键、值
4). 自动增新元素的键,在最大键值上加一
5). 关联数组的下标,不会影响到索引数组下标的自动增长
跟之前"直接赋值"声明数组是一样的
$arr = array('one', 'second'=>'two', 9=>'three', 'four'); print_r($arr); // Array ( [0] => one [1] => two [2] => three [3] => four )
中括号声明数组
PHP5.4以后,可以像JS语言一样声明数组了
<script> var arr = [1,2,3,4,5,6]; alert(arr[1]); // 2 </script>
PHP5.4以后支持了这种,直接使用中括号的声明数组
$arr = ['one', 'two', 'three', 'four']; print_r($arr); // Array ( [0] => one [1] => two [2] => three [3] => four )
中括号声明数组的方式和array()是一样的,只是形式不一样其它都一样
$arr = ['one', 'second'=>'two', 9=>'three', 'four']; print_r($arr); // Array ( [0] => one [second] => two [9] => three [10] => four )
"中括号"声明数组,还有一个新的功能:
如果函数里面返回一个数组,如果PHP5.4之前,函数的执行先赋给一个临时变量,然后再临时变量显示出数组内容
function demo(){ return array('one', 'two', 'three', 'forth'); } $arr = demo(); // 返回的数组赋给一个临时变量$arr echo $arr[0]; // one
新版本里,直接调用函数执行 + 数组下标
function demo(){ return array('one', 'two', 'three', 'forth'); } echo demo()[1]; // two
5、删除数组中的元素
特征10:删除数组中的一个元素,使用的是unset(),数组下标不会重新索引,需要使用array_value()函数重新索引
删除变量时用的是unset()函数
让变量不存在,有两种办法,一种是unset()函数将内存中的变量释放掉了
$a = 123; unset($a); // 执行到这,将内存中的变量释放掉了 if(isset($a)){ // isset判断变量是否存在 echo '存在'; }else{ echo '不存在'; // 不存在 }
或者将变量$a赋值为空null,跟unset()函数的作用是一样的
$a = 123; $a = null; if(isset($a)){ echo '存在'; }else{ echo '不存在'; // 不存在 }
使用unset()删除数组中的元素
$arr = ['one', 'two', 'three', 'four', 'five', 'six']; unset($arr[2]); if(isset($arr[2])){ echo '存在'; }else{ echo '不存在'; // 不存在 }
或者$arr[2]赋值为null,isset判断也是不存在的
$arr = ['one', 'two', 'three', 'four', 'five', 'six']; $arr[2] = null; if(isset($arr[2])){ echo '存在'; }else{ echo '不存在'; // 不存在 }
如果用 $arr[2] = null 删除一个数组元素后,用print_r($arr)打印数组,arr[2]单元还在,只是值没有了
$arr = ['one', 'two', 'three', 'four', 'five', 'six']; $arr[2] = null; print_r($arr); // Array ( [0] => one [1] => two [2] => [3] => four [4] => five [5] => six ) /*** arr[2]赋值为null的结果 Array ( [0] => one [1] => two [2] => [3] => four [4] => five [5] => six ) ***/
用unset(arr[2])删除,数组没有了这个$arr[2]单元
$arr = ['one', 'two', 'three', 'four', 'five', 'six']; unset($arr[2]); print_r($arr); // Array ( [0] => one [1] => two [3] => four [4] => five [5] => six ) /*** unset(arr[2])删除结果 Array ( [0] => one [1] => two [3] => four [4] => five [5] => six ) ***/
所以在数组里面用unset($arr[2])删除,和赋值为空$arr[0] = null还不太一样。
$arr[0] = null; 值为空
unset($arr[2]); 整个变量没有了,虽然整个变量没有了,但是下标的顺序并没有重新索引,
实例,猴子选大王
比如有15只猴子,随便指一个猴子(比如,3),从3开始数数,每次数到3的倍数时,就把那个就踢出去……,最后剩下的就是大王
/** * xdw($m, $n) * $m 猴子的数量 * $n 随便指的一个数 * */ function xdw($m, $n){ $arr = array(); // 声明一个空数组 $a = 'a'; for($i=0; $i<$m; $i++){ $arr[] = $a++; // 字符串的加加,是abcd……的累积 } // print_r($arr); // 打印出猴子 // 下面开始选大王 $i = 0; // 从0开始,下面while里面每循环一次$i++(不能从1开始,不然结果永远数到第0个) while(count($arr) > 1){ // 数组的个数大于1,就一直循环 if($i%$n == 0){ // 与$n取余的就删掉 unset($arr[$i]); // 1 把猴子踢出去,删除一个 }else{ $arr[] = $arr[$i]; // 2 踢出去的猴子(3)就不要了,数过的没踢出去的猴子(1,2),放到$arr数组后面 unset($arr[$i]); // 3 数过的猴子,原地删除,这样数组的长度每隔3个单元就少一个单元 } $i++; } return $arr; // 返回的数组里面,剩下的一个就是大王 } print_r(xdw(31, 3)); // Array ( [88] => ad )
6、多维数组
PHP中的数组,除了关联数组 和 索引数组,根据下标类型区分之外,还有维度上的区别。有一维数组、二维数组,三维数组,以及多维数组,二维以上都称为多维数组
我们知道,数组里面可以装任何类型,整形、字符串型、浮点型、布尔型,数组里面也可以再装一个数组
其实在PHP里面没有二维、多维数组这样的说法,都叫做数组中的数组
只不过经历过C语言,JAVA语言的数组使用,习惯上管PHP数组的数组叫二维数组,其实叫数组的数组更合适。说白了就是在数组里面再存放数组。
二维数组(数组中的数组)
比如,在一个数组里面,声明三个人的联系信息
/** * 第一个人$personOne * 第二个人$personTwo * 第三个人$personThree * 用关联数组来声明这种和生活中业务相关的,通过记下标名称比较方便 * */ $personOne = array('name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'); $personTwo = array('name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'); $personThree = array('name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'); /** * 一个人用,一个一维数组, * 把三个人的数组,放到一组$group里 * */ $group = array($onePerson, $twoPerson, $threePerson); print_r($group); echo $group[1]['name']; // Zhu
平时是这么做的,数组是可以嵌套的
$group = array( array('name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'), array('name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'), array('name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com') ); echo $group[1]['name'],'<br/>'; // Zhu $arr = $group[1]; echo $arr['email']; // Zhu@ruyic.com
第三个数组用字符串下标
$group = array( array('name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'), array('name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'), 'three'=>array('name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com') ); echo $group['three']['email'],'<br/>'; // Yu@ruyic.com
总结:
二维数组的声明方式,重点就是二维数组就是"数组的数组",跟一维数组访问上、结构上都一样,只不过数组里面多了一层而已。
三维数组:
三维数组的声明(在PHP5.4版本以后,可以像js里面用中括号的方式声明数组)
/*** $groupOne = [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ]; $groupTwo = [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ]; $groupTree = [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ]; ***/ /** * 把三个数组组成一个班级,把三个数组组成一个班级, * 可以有关联数组,也可以有索引数组 * */ $class = [ [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ], 'two' =>[ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'41', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ], [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'39', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'] ] ]; echo '<pre>'; print_r($class); echo '<pre/>'; echo $class['0'][1]['age'],'<br/>'; // 21 echo $class['two'][1]['age'],'<br/>'; // 41 echo $class[1][1]['age']; // 39
使用数组尽量控制在三维以内
多维数组还可以使用"直接赋值"的方式声明
$group[0]['name'] = 'Lin'; $group[0]['age'] = 20; $group[1]['name'] = 'Zhu'; $group[1]['age'] = 32; echo '<pre>'; print_r($group); echo '</pre>'; /*** Array ( [0] => Array ( [name] => Lin [age] => 20 ) [1] => Array ( [name] => Zhu [age] => 32 ) ) ***/
通常这种"直接赋值声明法"是操作某一个或者是添加某一个的处理会方便些。
另外PHP的二维数组,三维数组有一个特点,不用像C语言的数组那样,必须是行列要对齐。
什么是行列对其?
要求数组是几行几列,就必须是几行几列,这才是真正的二维。而PHP数组,里面的数组可以是混合式的。
什么是混合式的?
一个数组里面可以装数组成员,和非数组成员的混合也是可以的。
比如,每个组里面除了组成员,还有组共有的信息,比如这个组所在的位置,这个组再班级的成绩,这些不属于某个人,而是属于组信息。
所以我们可以在数组里面存,数组和非数组的混合体。
总结
1). 二维数组中,并不一定二维中必须是数组,
2). 二维数组中,二维数组的长度,不一定非要相等
如果外层数组的下标都是[0],里层的二维数组不指定下标,那么里面的二维数组下标从0开始自动增长
$group[0][] = 'Lin'; $group[0][] = 20; $group[0][] = 'Zhu'; $group[0][] = 32; print_r($group); // Array ( [0] => Array ( [0] => Lin [1] => 20 [2] => Zhu [3] => 32 ) ) /*** Array ( [0] => Array ( [0] => Lin [1] => 20 [2] => Zhu [3] => 32 ) ) ***/
如果里层数组不指定下标,外层数组也不指定下标,外层数组自动从0增长,这种情况不多,了解一下就行了
$group[][] = 'Lin'; $group[][] = 20; $group[][] = 'Zhu'; $group[][] = 32; print_r($group); // Array ( [0] => Array ( [0] => Lin ) [1] => Array ( [0] => 20 ) [2] => Array ( [0] => Zhu ) [3] => Array ( [0] => 32 ) ) /*** Array ( [0] => Array ( [0] => Lin ) [1] => Array ( [0] => 20 ) [2] => Array ( [0] => Zhu ) [3] => Array ( [0] => 32 ) ) ***/
如果外层不指定下标,里层数组下标的默认值都是[1],里面的数组下标都是[1],外层数组自动从0增长
$group[][1] = 'Lin'; $group[][1] = 20; $group[][1] = 'Zhu'; $group[][1] = 32; print_r($group); // Array ( [0] => Array ( [1] => Lin ) [1] => Array ( [1] => 20 ) [2] => Array ( [1] => Zhu ) [3] => Array ( [1] => 32 ) ) /*** Array ( [0] => Array ( [1] => Lin ) [1] => Array ( [1] => 20 ) [2] => Array ( [1] => Zhu ) [3] => Array ( [1] => 32 ) ) ***/
总结规律
多维数组是外层(第一层)的下标先自动增长,
如果外面第一层数组下标给值,里面第二层的下标自动增长
外面的第一个数组下标是[9],自动增长的规律是一样的,下标从[10]开始
$group[9][] = 'Lin'; $group[][] = 20; $group[][] = 'Zhu'; $group[][] = 32; // print_r($group); // Array ( [9] => Array ( [0] => Lin ) [10] => Array ( [0] => 20 ) [11] => Array ( [0] => Zhu ) [12] => Array ( [0] => 32 ) ) /*** Array ( [9] => Array ( [0] => Lin ) [10] => Array ( [0] => 20 ) [11] => Array ( [0] => Zhu ) [12] => Array ( [0] => 32 ) ) ***/
直接赋值声明二维数组用的比较少,arrar()声明数组的方式用的非常的多。
课程PPT里面的二维数组,该用关联的用关联下标去访问,该用索引的用索引下标去访问
$contact = array( array(1, '高某', 'A公司', '北京市', '(010)98765432', 'gm@linux.com'), array(2, '洛某', 'B公司', '上海市', '(021)12345678', 'lm@apache.com'), array(3, '峰某', 'C公司', '天津市', '(022)24680246', 'fm@mysql.com'), array(4, '书某', 'D公司', '重庆市', '(023)13579135', 'sm@php.com') ); echo '第一个人联系的公司:',$contact[0][2],'<br/>'; // 第一个人联系的公司:A公司 $contact = array( '北京联系人'=>array(1, '高某', 'A公司', '北京市', '(010)98765432', 'gm@linux.com'), '上海联系人'=>array(2, '洛某', 'B公司', '上海市', '(021)12345678', 'lm@apache.com'), '天津联系人'=>array(3, '峰某', 'C公司', '天津市', '(022)24680246', 'fm@mysql.com'), '重庆联系人'=>array(4, '书某', 'D公司', '重庆市', '(023)13579135', 'sm@php.com') ); echo '上海联系人的EMAIL:',$contact['上海联系人'][5]; // 上海联系人的EMAIL:lm@apache.com
PPT里的三维数组
$wage = array( '市场部'=>array( array(1, '高某', '市场部经理', 5000.00), array(2, '洛某', '职员', 3000.00), array(3, '峰某', '职员', 2400.00) ), '产品部'=>array( array(1, '李某', '产品部经理', 6000.00), array(2, '周某', '职员', 4000.00), array(3, '吴某', '职员', 3200.00) ), '财务部'=>array( array(1, '郑某', '财务部经理', 4500.00), array(2, '王某', '职员', 2000.00), array(3, '冯某', '职员', 1500.00) ) ); print_r($wage['市场部']); print_r($wage['市场部'][1]); print_r($wage['市场部'][1][3]);
6、遍历数组
使用数组最主要的目的就是批量操作,批量操作最核心的是遍历数组,PHP里面对数组的遍历比其它的语言要多一些,因为PHP语言数组的结构比别的语言灵活一些。
数组的便利方式:
1. 使用for语句循环遍历数组
2. 使用foracha语句便利数组
3. 联合使用list()、each()和while循环遍历数组
4. 使用数组的内部指针控制函数遍历数组
最主要的是for循环、PHP里面专门遍历数组的是foreach,还可以使用系统函数结合while循环去遍历数组
for语句遍历数组
高洛峰老师课程里说:for循环遍历数组效率很高,因为就是数组的访问方式,只不过是循环取值。就是一个循环的效率,所以效率很高,功能越全的效率越低。
下面使用array()语句将联系人列表中第一条记录,声明成一维数组,然后以表格的形式输出一维数组中的每一个单元
$contact = array(1, '高某', 'A公司', '北京市', '(010)12345678', 'gao@broPHP.com'); echo '<table border="1" width="600" align="center"> <caption><h1>联系人列表</h1></caption> <tr bgcolor="#ddd"> <th>编码</th> <th>姓名</th> <th>公司</th> <th>地址</th> <th>电话</th> <th>EMAIL</th> </tr> <tr>'; $nums = count($contact); // count()获取数组的长度 // 使用for循环,输出一维数组中的元素 for($i=0; $i<count($contact); $i++){ 优化一下,用计算好的数组长度$nums for($i = 0; $i < $nums; $i++){ echo "<td>{$contact[$i]}</td>"; } echo '</tr></table>';
如果数组的下标不是连续的,其中一个数组下标变成12,这个下标12元素后面的就遍历不出来了
count()获取数组的实际元素的个数
下标[12]超过了数组的实际长度,后面的就循环不到了
$arr = array('one', 'two', 'three', 'four', 'five', 12=>'six', 'seven', 'eight', 'nine', 'ten'); $nums = count($arr); for($i = 0; $nums > $i; $i++){ echo $arr[$i],'<br>'; } /*** one two three four five Notice: Undefined offset: 5 in…… Notice: Undefined offset: 6 in…… Notice: Undefined offset: 7 in…… Notice: Undefined offset: 8 in…… Notice: Undefined offset: 9 in…… ***/
别的语言里面数组下标是连续的,PHP数组可以不是连续的,所以for循环便利,优点是效率高
for循环一定要保证,数组下标是连续的索引数组
for循环遍历能遍历数组,但不是主力方式。f
or循环是模拟其它语言遍历数组,但不是PHP主要遍历数组的方式
for循环不足的地方
1). 数组下标不一定是连续的
2). 关联数组for循环不能遍历出值
索引数组和关联数组混合在一起,可以用foreach来遍历数组
foreach是专门遍历数组的语句
遍历二维数组
$group = [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'], ['name'=>'Li', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zh', 'age'=>'41', 'sex'=>'女', 'email'=>'Zh@ruyic.com'], ['name'=>'Y', 'age'=>'34', 'sex'=>'男', 'email'=>'Y@ruyic.com'] ]; // print_r($group); echo '<table border="1" width="800" align="center">'; echo '<caption><h1>数组转为表格</h1></caption>'; foreach($group as $row){ echo '<tr>'; print_r($row); // 打印的一行,还是数组,这里要再foreach循环一次 echo '</tr>'; } echo '</table>';
再用foreach循环
$group = [ ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'], ['name'=>'Li', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zh', 'age'=>'41', 'sex'=>'女', 'email'=>'Zh@ruyic.com'], ['name'=>'Y', 'age'=>'34', 'sex'=>'男', 'email'=>'Y@ruyic.com'] ]; // print_r($group); echo '<table border="1" width="800" align="center">'; echo '<caption><h1>数组转为表格</h1></caption>'; foreach($group as $row){ echo '<tr>'; foreach($row as $col){ echo "<td> $col </td>"; // 循环一次输出一列 } echo '</tr>'; } echo '</table>';
联合使用list()、each()和while循环数组
list()和each()是函数,while是循环,这几个是不搭边的,但效率上和foreach查不多
list()函数
这个函数和其它函数用法不同,作用是将数组中的元素转为变量使用。
相当于将数组元素对应的转给成了对应的变量,而且还是顺序转换的
list($a, $b, $c) = array('one', 'two', 'three'); echo $a,'<br/>'; // one echo $b,'<br/>'; // two echo $c,'<br/>'; // three
只能转索引数组为变量,索引数组下标是连续
list($a, $b, $c) = array('one', 8=>'two', 'three'); echo $a,'<br/>'; // one echo $b,'<br/>'; // 没有输出 echo $c,'<br/>'; // 没有输出
下面第一个单元下标是字符串,list()函数不能转为变量
list($a, $b, $c) = array('first'=>'one', 'two', 'three'); // print_r(array('first'=>'one', 'two', 'three')); // Array ( [first] => one [0] => two [1] => three ) echo '<br/>'; echo $a,'-<br/>'; // two- echo $b,'-<br/>'; // three- echo $c,'-<br/>'; // - 没有输出,只有一个标记" - "
可以只接收数组的第一个单元、第二个单元
list($a, $b) = array('one', 'two', 'three'); echo $a,'<br/>'; // one echo $b,'<br/>'; // two
中间空出来,只接受数组的第一个和最后一个
list($a, , $c) = array('one', 'two', 'three'); echo $a,'<br/>'; // one echo $c,'<br/>'; // three
list()函数用的地方非常多
// explode分隔字符串后,返回的是数组 $str = 'hello_world'; list($name, $pro) = explode('_', $str); echo $name,'<br/>'; echo $pro,'<br/>';
list()按照从左到右的顺序接收数组单元
list($a, $b) = array(1 => '第一个单元', 'value' => '第一个单元', 0 => 'one', 'key' => 'one' ); echo $a,'<br/>'; // one echo $b,'<br/>'; // 出不来
each()函数
1. each()函数参数是一个数组作,返回值也是一个数组
2. each只处理当前的元素(默认当前元素是数组的第一个元素,然后指针指向第一个),将当前元素转为数组信息,处理完后,指针向下一个元素移动
3. 如果指针已经在结束位置了,在使用each()获取元素,返回false
each()函数返回的值是一个数组,该数组有固定四个元素,而且下标也是固定(1, value, 0, key)
1 和 value 代表值
0 和 key 代表下标
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; $res = each($arr); print_r($res); /*** Array ( [1] => 第一个单元 [value] => 第一个单元 [0] => one [key] => one ) ***/ echo $res['value'],'<br/>'; // 第一个单元 echo $res[1],'<br/>'; // 第一个单元 echo $res[0],'<br/>'; // one echo $res['key'],'<br/>'; // one
将当前元素转为数组信息,每一次执行完后,指针向下一个元素移动
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; // 第一次执行 $res = each($arr); echo $res['value'],'<br/>'; // 第一个单元 echo $res[1],'<br/>'; // 第一个单元 echo $res[0],'<br/>'; // one echo $res['key'],'<br/>'; // one // 第二次执行 $res = each($arr); echo $res['value'],'<br/>'; // 第二个单元 echo $res[1],'<br/>'; // 第二个单元 echo $res[0],'<br/>'; // 0 echo $res['key'],'<br/>'; // 0 // 第三次执行 $res = each($arr); echo $res['value'],'<br/>'; // 第三个单元 echo $res[1],'<br/>'; // 第三个单元 echo $res[0],'<br/>'; // 1 echo $res['key'],'<br/>'; // 1 // 再往后处理,返回布尔值false var_dump($res = each($arr)); // bool(false)
这就是each()的全部语法,他就这个作用
单纯使用each()没有什么意义,但是和list、while循环配合就有意义了
list(), each(), while循环,这三个配合起来遍历数组
首先while循环和each配合
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while($tmp = each($arr)){ print_r($tmp); echo '<br/>'; } /*** Array ( [1] => 第一个单元 [value] => 第一个单元 [0] => one [key] => one ) Array ( [1] => 第二个单元 [value] => 第二个单元 [0] => 0 [key] => 0 ) Array ( [1] => 第三个单元 [value] => 第三个单元 [0] => 1 [key] => 1 ) ***/
历出数组的下标和值
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while($tmp = each($arr)){ echo "{$tmp['key']} : {$tmp['value']}<br/>"; } /*** one : 第一个单元 0 : 第二个单元 1 : 第三个单元 ***/
将数组结构转成变量,就要用到list()函数,数组中有几个单元,list()中就用几个参数
each()函数返回的是数组,有索引下标、关联下标,而且下标是从0开始
list()里面写两个变量,变量$key接收索引[0],变量$value接收索引[1],把键和值转成变量,循环里操作的就是变量了
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while(list($key, $value) = each($arr)){ echo "$key : $value<br/>"; } /*** one : 第一个单元 0 : 第二个单元 1 : 第三个单元 ***/
如果只要值不要键呢?把第一个$key省略掉,预留出位置
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while(list(, $value) = each($arr)){ echo "$value<br/>"; } /*** 第一个单元 第二个单元 第三个单元 ***/
foreach能做到的,这个组合也能做到,但是这个组合有一个弊端,什么弊端呢?
each()有一个特点,指针循环结尾,就返回false
所以第一次循环后,再循环的条件是false,后面的循环就根本不执行
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; } /*** one : 第一个单元 0 : 第二个单元 1 : 第三个单元 ***/ while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; } while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; }
怎么把数组指针移回去呢?
这里简单的说一下,用reset()函数
$arr = ['one'=>'第一个单元', '第二个单元', '第三个单元']; while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; } reset($arr); while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; } reset($arr); while(list($key, $value) = each($arr)){ echo "$key => $value<br/>"; } /*** one => 第一个单元 0 => 第二个单元 1 => 第三个单元 one => 第一个单元 0 => 第二个单元 1 => 第三个单元 one => 第一个单元 0 => 第二个单元 1 => 第三个单元 ***/
用这个组合,遍历表格
$group = [ 'groupName'=>'第三组', 'groupPrice'=>'888元', ['name'=>'Lin', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zhu', 'age'=>'21', 'sex'=>'女', 'email'=>'Zhu@ruyic.com'], ['name'=>'Yu', 'age'=>'34', 'sex'=>'男', 'email'=>'Yu@ruyic.com'], ['name'=>'Li', 'age'=>'32', 'sex'=>'男', 'email'=>'lin@ruyic.com'], ['name'=>'Zh', 'age'=>'41', 'sex'=>'女', 'email'=>'Zh@ruyic.com'], ['name'=>'Y', 'age'=>'34', 'sex'=>'男', 'email'=>'Y@ruyic.com'] ]; echo '<table border="1" width="800" align="center">'; echo '<caption><h1>数组转为表格</h1></caption>'; while(list($key, $row) = each($group)){ echo '<tr>'; if(is_array($row)){ while(list(, $col) = each($row)){ echo "<td> $col </td>"; // 循环一次输出一列 } }else{ echo '<td colspan="4">'.$key.': '.$row.'</td>'; } echo '</tr>'; } echo '</table>';
这个组合效率上和foreach差不多,但使用复杂性上比foreach高
二、十八哥的课程笔记
数组中最重要的两个概念
1. key,键/key/index/索引/下标
编号是数字时叫索引/index,字符时叫键(key)/下标
2. 值/value
数组的声明中,体现的是 键 与 值 的对应,数组就是"键值对"的集合
$stu = array('1', 'name'=>'张三', 'height'=>176, 'area'=>'衡山', 'grade'=>'高三'); print_r($stu); // Array ( [0] => 1 [name] => 张三 [height] => 176 [area] => 衡山 [grade] => 高三 )
1、数组的创建
创建数组的两种方式
1. 初始化创建方式
2. 使用array结构创建数组
数组最本质的是"键值对",重要的是把"键 与 值"的对应关系体现出来
初始化(直接赋值)的方式创建数组
$stu = null; $stu['name'] = '张三'; $stu['height'] = 176; $stu['area'] = '衡水'; $stu['grade'] = '高三'; print_r($stu); // Array ( [name] => 张三 [height] => 176 [area] => 衡水 [grade] => 高三 )
array()结构来创建
$stu = array('name'=>'李四', 'height'=>176, 'area'=>'衡水', 'grade'=>'高三'); print_r($stu); // Array ( [name] => 李四 [height] => 176 [area] => 衡水 [grade] => 高三 )
这两种方法都可以创建数组
虽然形式上不同,但他们本质上有"相通之处",
既,都是声明"键与值的对应"
有时候需要增加一个单元
初始化方式,便于运行中,临时增加一个单元
$stu = array('name'=>'李四', 'height'=>176, 'area'=>'衡水', 'grade'=>'高三'); $stu['waring'] = '晚不归宿'; print_r($stu); // Array ( [name] => 李四 [height] => 176 [area] => 衡水 [grade] => 高三 [waring] => 晚不归宿 )
数组创建,之懒人方式
声明数组时,不写键行不行?
可以的,这种情况下,键会从0开始,逐一自动增加
$flower = array('梅', '兰', '竹', '菊'); print_r($flower); // Array ( [0] => 梅 [1] => 兰 [2] => 竹 [3] => 菊 )
直接赋值的方式,只写值不写值,键会从0开始,逐一自动增加
$stars[] = '刘德华'; $stars[] = '张学友'; $stars[] = '郭富城'; $stars[] = '黎明'; print_r($stars); // Array ( [0] => 刘德华 [1] => 张学友 [2] => 郭富城 [3] => 黎明 )
马虎者的创建方式,有单元写了键,有的单元没写键
1). 如果指定了键,则以指定的为准
2). 如果没指定,则从0开始,逐一递增
$yan = array('name'=>'燕十八', 'age'=>28, 174, '安徽'); print_r($yan); // Array ( [name] => 燕十八 [age] => 28 [0] => 174 [1] => 安徽 )
如果没指定,则从0开始,逐一递增。这句话说的不够准确
手册上最官方的权威解释:
如果方括号没有给出键名,则取当前最大整数索引值,新键名将该值 + 1。
如果当前还没有整数索引,则键名为0,
如果指定的键名已经有值了,该值将被覆盖。
下面数组的键是各是多少?
$class[] = '张三'; // 0 $class[] = '李四'; // 1 $class[5] = '王五'; // 5 $class[] = '赵六'; // 6 $class[] = '郑七'; // 7 print_r($class); // Array ( [0] => 张三 [1] => 李四 [5] => 王五 [6] => 赵六 [7] => 郑七 )
如何来理解这句:如果指定的键名已经有值了,该值将被覆盖。
下面打印$butty是什么样呢?武藤兰覆盖了苍井空
$butty[] = '林志玲'; // key: 0 $butty[] = '苍井空'; // 被覆盖 $butty[1] = '武藤兰'; // key: 1 $butty[2] = '小泽'; // key: 2 print_r($butty); // Array ( [0] => 林志玲 [1] => 武藤兰 [2] => 小泽 )
上面三个例子,讨论出键值的增长关系。
看一个陷阱
删掉了一个单元,键的增长不受影响,新增的单元的键继续往上增加
$arr = array('春', '夏', '秋', '冬'); print_r($arr); // Array ( [0] => 春 [1] => 夏 [2] => 秋 [3] => 冬 ) unset($arr[3]); // 删除最后一个单元 "冬" echo '<br/>'; print_r($arr); // Array ( [0] => 春 [1] => 夏 [2] => 秋 ) /** * 最后一个单元"冬",被删除了 * 再增加一个单元,新增单元的键是多少? * 0 1 2 4 * */ $arr[] = '季节'; // 新增一个单元 "季节" echo '<br/>'; print_r($arr); // Array ( [0] => 春 [1] => 夏 [2] => 秋 [4] => 季节 )
2、数组的操作
1 如何读数组中一个单元的值?
2 数组的一个单元,能容纳什么类型的值?
3 如果给数组增加一个单元?
4 如何修改数组中一个单元的值?
5 如何删掉一个数组的单元?
通过"键"读取一个单元的值,在js语言里面和C语言里面,数组是不能用字符串来做键(key)的,但是在PHP里面数组非常灵活
$arr = array('person', 'age'=>28, 'height'=>176); echo $arr[0],'<br/>'; // person echo $arr['age']; // 28
数组的一个单元,能容纳什么类型的值?
$class['stuOne'] = array('name'=>'张三', 'age'=>28); print_r($class); // Array ( [stuOne] => Array ( [name] => 张三 [age] => 28 ) ) /*** Array ( [stuOne] => Array ( [name] => 张三 [age] => 28 ) ) ***/ // 打印内层二维数组中,第二个数组的单元 echo '<br/>',$class['stuOne']['age']; // 28
一般超过二维的,叫"多维数组"
如何给数组增加一个单元?增加非常简单,直接赋值就行了,可以指定键,也可以不指定键
$arrAdd = array('春', '夏'); $arrAdd[] = '秋'; $arrAdd[] = '冬'; print_r($arrAdd); // Array ( [0] => 春 [1] => 夏 [2] => 秋 [3] => 冬 )
如何修改数组中一个单元的值?指定要修改的单元,并赋值就可以了
$arrEdit = array('春', '夏', '秋', '冬'); $arrEdit[2] = 'autumn'; $arrEdit[3] = 'winter'; print_r($arrEdit); // Array ( [0] => 春 [1] => 夏 [2] => autumn [3] => winter )
如何删掉一个数组的单元?使用unset()函数删除
$arrDel = array('春', '夏', '秋', '冬'); print_r($arrDel); // Array ( [0] => 春 [1] => 夏 [2] => 秋 [3] => 冬 ) unset($arrDel[3]); // 删除下标是[3]的单元 "冬"" echo '<br/>'; print_r($arrDel); // Array ( [0] => 春 [1] => 夏 [2] => 秋 )
PHP语言非常灵活
在C语言中,js中,JAVA中,数组的索引只能是数字,而在PHP中,KEY/Index可以是字符串,也可以是数字
如果索引是纯数字称为"索引数组",否则称之为"关联数组"
什么栈、列表、队列、list,在PHP中一个数组搞定。
3、遍历数组
for循环遍历数组
默认情况下,数组的键从0开始,逐一递增,有规律可循环
count()函数计算数组的单元个数。数组的最大索引值,是数组的单元个数 - 1
$arr = array('春', '夏', 'autumu', 'winter', '雨'); for($i = 0, $len = count($arr); $i < $len; $i++ ){ echo $arr[$i],'~<br/>'; } /*** 春 夏 autumu winter 雨 ***/
优化一下for循环的细节,提告运行效率
$arr = array('春', '夏', 'autumu', 'winter', '雨'); for($i = 0, $len = count($arr); $i < $len; $i++ ){ echo $arr[$i],'<br/>'; }
foreach方式遍历数组
$arr = array(3=>'春', 2=>'夏', 5=>'秋', 9=>'冬'); // foreach是怎么工作的? foreach($arr as $key=>$value){ // 循环数组的每个单元,每一次循环时,把当前循环的单元"键"赋给$key、"值"赋给$value echo $key,'~',$value,'<br/>'; } /*** 3~春 2~夏 5~秋 9~冬 ***/
如果最后在foreach循环外面,再打印$key、$value,输出的是什么
foreach($arr as $key=>$value){ echo $key,'~',$value,'<br/>'; } echo $key,'=',$value; // 输出的是数组最后一对键值:9 = 冬
停留在最后一次$key和$value赋值的状态
foreach第二种用法,循环只取数组的值
$arr = array(3=>'春', 2=>'夏', 5=>'秋', 9=>'冬'); foreach($arr as $value){ // 循环数组的每个单元,把单元的值赋给$value echo $value,'<br/>'; } /**** 春 夏 秋 冬 ***/
如果只要数组的键key,不想要数组的值呢?
这样不行,因为指定变量$key和变量$value是我们自己定义的临时变量,用来放读出来的键和值
就算变量名是$key,语法也是把数组的值取出来赋给了$key
$arr = array(3=>'春', 2=>'夏', 5=>'秋', 9=>'冬'); foreach($arr as $key){ echo $key,'<br/>'; // 打印的还是值 } /*** 春 夏 秋 冬 ***/
可以这样取得单独键
$arr = array(3=>'春', 2=>'夏', 5=>'秋', 9=>'冬'); foreach($arr as $key=>$value){ echo $key,'<br/>'; } /*** 3 2 5 9 ***/
直播同学让燕十八老师看的面试题
这个题牵扯到运算符优先级的问题
1). if($a = 7 && $b == 7)
7 && $b 优先级高,优先发挥的作用
2). 得到的$a是true,true++还是true
3). 索引$a输出的是 1
$a = 5; $b = 7; if($a = 7 && $b == 7){ $a ++; $b ++; } echo $a, '~' ,$b; // 1~8
顺便练习一个题
$b = 5; if($a = 8 && $b = 9){ $a = $a + 1; $b = $b + 1; } echo $a, '~', $b; // 2~10
4、数组的游标操作
游标操作在开发中没有foreach用的频繁,但是通过游标操作,可以更加深入解底层,去了解数组是怎么循环的。
数组有N个单元,同时只能操作一个单元
比如在循环中,也是循环出一个单元,读取一个单元的,如果读取完第一个单元,下次再来读取时,怎么记住该读取第二个单元了呢?
在数组内部,有一个指针,指针指着某一个单元。每循环一个单元,指针往尾部移动
数组的游标操作主要有下面几个函数
current()
key()
next()
prev()
reset()
end()
current英语里有"当前的"意思,该函数是取出,数组内部指针,指向当前单元的"值"。
一个数组刚刚定义,指针指向第0个单元,执行current($arr)打印的是第0单元的值
第二次执行current($arr)打印的和第一次一样,因为数组下标没有完后移动
$arr = array('春', '夏', '秋', '冬'); echo current($arr),'<br/>'; // 春 echo current($arr),'<br/>'; // 春 /** * key函数是,取出数组内部指针,指向的单元"键" * 执行两次key($arr)函数,打印的都是 0 * 因为此时指针还是指向第0个单元 * */ echo key($arr),'<br/>'; // 0 echo key($arr),'<br/>'; // 0
next英语里有"下一个"的意思,把数组内部指针往尾部移动一个单元
执行current($arr),再执行key($arr),指针继续往后走
$arr = array('春', '夏', '秋', '冬'); next($arr); echo current($arr),'<br/>'; // 夏 echo key($arr),'<br/>'; // 1 next($arr); echo current($arr),'<br/>'; // 秋 echo key($arr),'<br/>'; // 2 next($arr); echo current($arr),'<br/>'; // 冬 echo key($arr),'<br/>'; // 3 /** * next($arr)再往后走 * current($arr) 读不到值,返回布尔类型false * key($arr) 下标返回空null * */ next($arr); var_dump(current($arr)); // bool(false) var_dump(key($arr)); // NULL
手册:
mixed current( array $array );
每个数组中都有一个内部的指针指向他"当前的"单元,初始时指针指向数组中的第一个单元
current()函数返回内部指针,指向的数组单元的值,并不移动指针。
如果内部指针指向超过单元列表的末端,current()返回FALSE
如果数组包含空的单元(0或"")current()函数也返回FALSE。
要正确的遍历可能含有空单元的数组,用each()函数
miexd next( array $array );
返回数组指针,指向下一个单元的值,最后一个单元在往后时返回FALSE
如果数组包含空的单元"",或单元的值是0,next()函数也返回FALSE。
要正确的遍历可能含有空单元"",或单元的值为0的数组,参见each()函数
能不能从后到前打印出来?
既,先把指针指向数组最后,然后逐步往前移动指针
默认指针指向第0个单元
end() 该函数把指针指向数组的最后一个单元
prve() 从后向前移动指针
$arr = array('春', '夏', '秋', 'winter'); end($arr); // 将数组指针指向最后 echo current($arr),'<br/>'; // winter echo key($arr),'<br/>'; // 3 prev($arr); // 把指针往前移动 echo current($arr),'<br/>'; // 秋 echo key($arr),'<br/>'; // 2 prev($arr); // 把指针往前移动 echo current($arr),'<br/>'; // 夏 echo key($arr),'<br/>'; // 1 prev($arr); // 把指针往前移动 echo current($arr),'<br/>'; // 春 echo key($arr),'<br/>'; // 0 prev($arr); // 把指针往前移动 echo current($arr),'<br/>'; // 什么都看不到 echo key($arr),'<br/>'; // 什么都看不到 /** * 不是什么都看不到 * 因为false打印出来是空字符串 * null打印出来还是空字符串 * 用var_dump打印 * */ var_dump(current($arr)); // bool(false) var_dump(key($arr)); // NULL
利用next()和prve()来循环数组
用reset()函数可以重置数组指针
$arr = array('春', '夏', '秋', 'winter'); reset($arr); echo current($arr),'<br/>'; // 春 echo key($arr),'<br/>'; // 0 //连续两次next() next($arr); next($arr); echo current($arr),'<br/>'; // 秋 echo key($arr),'<br/>'; // 2 reset($arr); // 执行reset() echo current($arr),'<br/>'; // 春 echo key($arr),'<br/>'; // 0
现在有六个函数:curentt()、key()、next()、prve()、reset()、ned()
单独用for循环,是没法处理关联数组的,但是结合游标操作之后,就可以循环处理了
$arr = array('name'=>'张三', 'age'=>28, 'height'=>176, 'area'=>'山西'); for(; current($arr); next($arr)){ echo key($arr),'~',current($arr),'<br/>'; }
这里只是为了练习游标操作,实际开发中用foreach
游标处理数组非常灵活
打印一个单元,跳过过一个单元,再打印……怎么实现?
写两次next()
$arr = array('荣', '耀', '只', '属', '于', '真', '正', '上', '场', '的', '人'); for(; current($arr); next($arr),next($arr)){ echo key($arr),'~',current($arr),'<br/>'; } /*** 比foreach还灵活 0~荣 2~只 4~于 6~正 8~场 10~人 ***/
走两步退一步,怎么用游标实现
$arr = array('荣', '耀', '只', '属', '于', '真', '正', '上', '场', '的', '人'); $flag = true; // reset($arr); // 重置数组 for(; current($arr); ){ echo key($arr),'~',current($arr),'<br/>'; if($flag){ next($arr); next($arr); $flag = false; }else{ prev($arr); echo key($arr),'~',current($arr),'<br/>'; $flag = true; } }
foreach不是函数,是语言结构
当foreach开始执行时,数组内部指针会自动指向第一个单元。这意味着在foreach循环之前系统自动调用reset()
执行两次foreach都是从数组开头开始打印
$arr = array('a', 'b', 'c', 'd'); foreach($arr as $v){ echo $v,'<br/>'; } foreach($arr as $v){ echo $v,'<br/>'; }
总之,foreach在运行前会自动reset()重置数组,因此foreach不会受上一次的影响
$arr = array('a', 'b', 'c', 'd'); echo current($arr),'<br/>'; // a foreach($arr as $v){ echo $v,'<br/>'; } // PHP5:foreach结束后,并没有马上帮我们把指针初始化 //var_dump(current($arr)); // bool(false) ,PHP5 // PHP7执行完后马上把游移回了数组头一位 var_dump(current($arr)); //string(1) "a" ,PHP7
看一个小陷阱
1). 第一个单元的值为0,
2). 0转成布尔值为假false,
3). 因此for循环直接跳出了
所以下面的循环没有任何输出
$arr = array(0, 1, 2, 3, 4); for( ;current($arr); next($arr)){ echo current($arr),'<br/>'; }
再看下面
for循环遇到值为0的时就结束
因此只打印出-3、-2、-1,当指向0的时候,0为假for循环就退出了
如果数组某个单元的值为空字符串""、0、false、null,都将导致循环退出
解决方法each()函数
echo '<hr/><br/><br/><br/>'; $arr = array(-3, -2, -1, 0, 1, 2, 3, 4); for( ;current($arr); next($arr)){ echo current($arr),'<br/>'; } /*** -3 -2 -1 ***/
5、list()与each()
each()函数
each在英语里有"每一个"的意思,each()函数就是用来遍历数组用的,他能把数组中的每一个单元拿出来,而且该函数拿出来的数组单元值非常有特点。
作用:是把指针,指向的当前单元的信息组成一个数组返回,并且把指针向数组尾部移动一次。
特点:返回一个数组,有四个单元,放了两样信息,当前单元的键和值,返回数组的四个单元格式(1、value、0、key)是固定的 。
1 值
value 值
0 当前指针
key 当前指针
$arr = array('东', '邪', '西', '毒'); print_r(each($arr)); // Array ( [1] => 东 [value] => 东 [0] => 0 [key] => 0 ) /*** * 第一次执行each() * 第一个单元的key是0,value是"东" * * Array * ( * [1] => 东 值 * [value] => 东 值 * [0] => 0 当前指针 * [key] => 0 当前指针 * ) * * [1]和[value]是值 * [0]和[key] 是键 * 关联和索引各一次 * */ print_r(each($arr)); // Array ( [1] => 邪 [value] => 邪 [0] => 1 [key] => 1 ) echo '<br/>'; /*** * 第二次执行 * Array * ( * [1] => 邪 * [value] => 邪 * [0] => 1 * [key] => 1 * ) * */ print_r(each($arr)); echo '<br/>'; print_r(each($arr)); echo '<br/>'; /*** * 再执行两次each($arr),指针再往后走二次 * * Array * ( * [1] => 西 * [value] => 西 * [0] => 2 * [key] => 2 * ) * * Array * ( * [1] => 毒 * [value] => 毒 * [0] => 3 * [key] => 3 * ) * */ /** * 再往后执行each($arr)就看不到什么东西了 * 用var_dump(each($arr))查看,返回bool(false) * */ echo '<br/>'; print_r(each($arr)); echo '<br/>'; var_dump(each($arr)); // bool(false)
总结:
each()函数取出指针所指单元的键和值,组合成一个数组返回,并把指针向后移动,如果取不出单元返回false
根据eacha()函数的特点,用while循环遍历数组
如果取出单元,则返回1、value、0、key四个固定格式的数组
如果指针超过界限,返回false,自然while结束
$arr = array(-3, -2, -1, 0, 1, 2, 3); while($ceil = each($arr)){ //echo $ceil[0], '=>', $ceil[1],'<br/>'; echo $ceil['key'], '=>', $ceil['value'],'<br/>'; }
list()函数
each()函数经常和list()函数一起用
list()函数是复合赋值语句,可以一次性为多个变量赋值
先看下面常见的操作,把数组中的单元赋给多个变量,然后在打印变量
$arr = array('东', '南', '西', '北'); $east = $arr[0]; $south = $arr[1]; $west = $arr[2]; $north = $arr[3]; echo $east,'<br/>'; // 东 echo $south,'<br/>'; // 南 echo $west,'<br>'; // 西 echo $north,'<br>'; // 北
list()函数可以一次性的给多个变量赋值
echo '<br/>'; $arr = array('春', '夏', '秋', '冬'); list($spring, $summer, $autumn, $winter) = $arr; echo $spring,'<br/>'; // 春 echo $summer,'<br/>'; // 夏 echo $autumn,'<br/>'; // 秋 echo $winter,'<br/>'; // 冬
list()函数赋值过程是怎么发生的呢?下面为什么没有打印出变量$a呢?
list($a, $b, $c) = array(2=>'赵', 3=>'钱', 1=>'孙'); // Notice: Undefined offset: 0 in if(isset($a)){ echo $a,'<br/>'; }else{ echo '没有变量$a<br/>'; // 没有变量$a } if(isset($b)){ echo $b,'<br/>'; // 孙 }else{ echo '没有变量$b<br/>'; } if(isset($c)){ echo $c,'<br/>'; // 赵 }else{ echo '没有变量$c<br/>'; }
list()函数是如何工作的?
因为list能给多个变量赋值,既、把数组的多个单元分别赋值给多个值。
那么,自然要注意一个最重要的地方,数组的哪个单元对应赋给哪个变量。
怎么样对应的呢?
在list($a, $b, $c)中变量按逗号隔开的顺序,从左到右分别对应,右侧数组$arr[0]、$arr[1]、$arr[2]
如果需要对应右侧的$arr[x]不存在怎么办?
依然先,对应能对应上的,不存在的当NUL来处理。
因此
$a 映射 $arr[0]
$b 映射 $arr[1]
$c 映射 $arr[2]
映射完成就该赋值了,赋值的过程和映射的顺序是反着的,是从右向左赋值
$c = $arr[2];
$b = $arr[1];
$a = $arr[0];
打印结果
$c = '赵';
$b = '孙';
$a = NULL; // $arr[0]不存在
$arr[1], , $arr[2] 注意这里有两个逗号
list($arr[0], $arr[1], , $arr[2]) = array(3=>'赵', 1=>'钱', 5=>'孙', 2=>'李', 0=>'燕'); print_r($arr); // Arrar([0]=>燕 [1]=>钱 [2]=>赵)
分析:
1).先从左到有映射,分配赋值的过程
$arr[0] 映射 array[0] 燕
$arr[1] 映射 array[1] 钱
多个一个逗号,往后跳一个
$arr[2] 映射 array[3] 赵
2).分配完,从右往左赋值
$arr[2] = '赵';
$arr[1] = '钱';
$arr[0] = '燕';
PHP5 数组打印是按创建的顺序
PHP7 Array ( [0] => 燕 [1] => 钱 [2] => 赵 )
each()函数加上list()函数,自己写一个模拟foreach函数,foreach是语法结构
$arr = array(3=>'赵', 1=>'钱', 5=>'孙', 2=>'李', 0=>'燕'); while(list($key, $value) = each($arr)){ echo $key, '~', $value, '<br/>'; } /*** 3~赵 1~钱 5~孙 2~李 0~燕 ***/
封装一个函数for_each($arr, $value)
$arr = array(3=>'赵', 1=>'钱', 5=>'孙', 2=>'李', 0=>'燕'); function for_each($arr){ while($tmp = each($arr)){ list($key, $value) = $tmp; echo $key, $value,'<br/>'; } } for_each($arr);
优化代码
$arr = array(3=>'赵', 1=>'钱', 5=>'孙', 2=>'李', 0=>'燕'); function for_each2($arr){ while(list($key, $value) = each($arr)){ echo $key, $value,'<br/>'; } } for_each2($arr);
6、数组的下标怎么写
数组的下标怎么写
1、整形(数字)的索引值,不必加单/双引号。比如['1']加了单/双引号,则需要隐式的把字符串"1"转换成整型1,会影响效率。
2、字符串型的下标,必须加单双引号。
3、加单引号还是双引号,单引号的解析速度远比双引号块,所以优先加双引号
如果字符串型下标不加单/双引号,虽然打印出了值,但出现警告Warning/注意Notice信息
/** * 虽然打印出了值(夏天)但出现提示警告信息 * PHP不同版本的信息有点小区别 * PHP7.3 Warning: Use of undefined constant …… * PHP5.3 Notice: Use of undefined constant …… * */ $arr = array(1=>'季节', 'spring'=>'春天', 'summer'=>'夏天', 'autumn'=>'秋天', 'winter'=>'冬天'); echo $arr[summer]; // PHP7 Warning: Use of undefined constant …… // 夏天
Notice是"注意"的意思
手册:索引(搜:errer reporting) -> error_reporting -> int error_reporting([int $leve1])
error_reporting(E_ALL & ~ E_NOTICE); 这句的意思是把Notice级别的错误信息屏蔽掉
error_reporting(E_ALL & ~ E_WARNING);同理,屏蔽warning级别的信息
屏蔽Notice/warning级别的错误信息,字符串下标没有加引号也能输出值
error_reporting(E_ALL & ~ E_NOTICE); error_reporting(E_ALL & ~ E_WARNING); $arr = array(1=>'季节', 'spring'=>'春天', 'summer'=>'夏天', 'autumn'=>'秋天', 'winter'=>'冬天'); echo $arr[summer]; // 夏天
继续探究,下面做两步
1). 字符串类型的下标[summer]依然不加单/双引号
2). 定义一个常量,常量名:summer,常量值:season
// error_reporting(E_ALL & ~ E_NOTICE); // error_reporting(E_ALL & ~ E_WARNING); $arr = array(1=>'季节', 'spring'=>'春天', 'summer'=>'夏天', 'autumn'=>'秋天', 'winter'=>'冬天'); define('summer', 'season'); // 定义一个常量summer echo $arr[summer]; // Notice: Undefined index: season in…… /** * 打开,屏蔽Notice/warning级别的错误信息 * PHP7输出:Notice: Undefined index: season in…… * PHP5不输出任何内容 * * 注释,屏蔽Notice/warning级别的错误信息 * PHP5 Notice: Undefined index: season in…… * */
注意信息:Notice: Undefined index: season…… 没有定义的索引season
提示说明PHP没有找数组的[summer]下标,而是找的是常量[season]
说明把$season[summer] -> 引用的是$season[season],没有[season]单元所以报Notice
总结规律:
$season[summer]没有加引号(单引或双引),理解成常量名summer,并且按照常量值来做下标$arr[season]
如果没有summer常量,再次把summer当成字符串的下标来处理。
不加单/双引号,流程上先理解成常量,如果没有常量,再当做字符串,效率上非常低。
字符串需要加单双引号,避免因常量定义而产生错误
如果在数组里面定义一个下标的键名为season,常量summer的值也是season,常量的值作为下标的键可以打印出数组对应的值。
说明不加单双引号,字符串下标确实是当先当做常量来解析,没有这个常量再当中字符串
$arr = array('season'=>'季节', 'spring'=>'春天', 'summer'=>'夏天', 'autumn'=>'秋天', 'winter'=>'冬天'); define('summer', 'season'); // 定义一个常量summer echo $arr[summer]; // 季节
1627097211