V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
koodai
V2EX  ›  PHP

PHP 的数组定义了键名,就不能使用索引了吗?

  •  
  •   koodai · 2017-01-14 15:08:54 +08:00 · 4849 次点击
    这是一个创建于 2900 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景:

    我的 PHP 数组定义了键名,情况如下:

    array(
        'filed1'=>array(1,2,3),
        'filed2'=>array(a,b,c),
        'filed3'=>array(x,y,z),
    );
    

    预期:

    我根据这个数组要生成 sql :

    INSERT INTO `contents` (`filed1`,`filed2`,`filed3`) VALUES ((1,a,x) ,(2,b,y) ,(3,c,z) ) ;
    

    问题:

        $value_str='(';
    	for($i=0;$i<count( $data[ 0 ] );$i++) // 记录数
    		{
    			for($j=0;$j<count($data);$j++)	// 字段数量
    			{
    				$value_str.="'".$data[$i][$j]."',";
    			}
    		}
    	$value_str.=')';
    	$filed_str='(`'.implode("`,`",array_keys($data)).'`)';
    

    就在记录数哪里,使用了索引值,$data[0]这样的方式,结果,就出问题了!数组越界 Undefined offset: 0

    SO:

    定义了键名的数组,就不能用索引来取值了吗?

    23 条回复    2017-01-16 15:11:32 +08:00
    koodai
        1
    koodai  
    OP
       2017-01-14 15:17:44 +08:00
    有没有大神顺手回复一下问题的 ^_^
    koodai
        2
    koodai  
    OP
       2017-01-14 15:20:56 +08:00
    现有方案:
    ```
    $data_array_keys = array_keys($data);
    $value_str='(';
    for($i=0;$i<count( $data[ $data_array_keys[0] ] );$i++) // 记录数
    {
    for($j=0;$j<count($data);$j++) // 字段数量
    {
    $value_str.="'".$data[$i][$j]."',";
    }
    }
    $value_str.=')';
    $filed_str='(`'.implode("`,`", $data_array_keys ).'`)';
    ```
    torbrowserbridge
        3
    torbrowserbridge  
       2017-01-14 15:23:24 +08:00
    array_values
    langmoe
        4
    langmoe  
       2017-01-14 15:24:17 +08:00
    for 改成 foreach ?
    koodai
        5
    koodai  
    OP
       2017-01-14 15:25:46 +08:00
    我回复的太着急了,$value_str.="'".$data[$i][$j]."',"; 这里也有问题,不过简单做下标的调换就可以 。$j 这里直接无法使用,需要根据 key 的值来取,
    koodai
        6
    koodai  
    OP
       2017-01-14 15:27:40 +08:00
    @langmoe 还有个计数的功能。
    如果使用 foreach ,可以先循环字段名,然后循环字段的值。

    就问题还存在,用了键名,就无法用下标了吗?以前都没注意过(⊙﹏⊙)b
    koodai
        7
    koodai  
    OP
       2017-01-14 15:29:01 +08:00
    @torbrowserbridge 把键名直接去掉,新的数组只含键值,再用下标,可以!好方法
    AbrahamGreyson
        8
    AbrahamGreyson  
       2017-01-14 15:29:55 +08:00 via iPhone
    代码风格倒腾明白了或许能帮你看看,这大 tab 在手机上都缩进到地平线了。
    koodai
        9
    koodai  
    OP
       2017-01-14 15:36:21 +08:00
    @AbrahamGreyson 不谈这个代码,简单一个问题,就问:对于有键名的数组,就不可以用索引的方式取值了?
    guoguoer
        10
    guoguoer  
       2017-01-14 15:46:10 +08:00 via iPhone
    @koodai 我的理解, php 里没有把数组和字典没分开。键值对的字典,需要用键去访问。在 php 里如果刚好键是从 0 开始的数字,就是数组了。

    所以用 foreach 更简单一致。
    mrgeneral
        11
    mrgeneral  
       2017-01-14 16:23:12 +08:00
    关联数组和索引数组的区别,关联数组不支持索引访问
    AbrahamGreyson
        12
    AbrahamGreyson  
       2017-01-14 17:02:08 +08:00 via iPhone
    @koodai 是的😽
    msg7086
        13
    msg7086  
       2017-01-14 18:01:00 +08:00 via Android
    你数组里哪有 0 => ?
    0 和 field1 都是索引,或者叫键。
    [5] 就是 [0 => 5],所以你才能用 0 键去访问啊。
    msg7086
        14
    msg7086  
       2017-01-14 18:02:56 +08:00 via Android
    你标题里说的:索引和键名,在 PHP 里是一个东西。
    jswh
        15
    jswh  
       2017-01-14 18:21:27 +08:00
    @koodai 是的。
    还有个坑,索引比如 0 和数字字符串键名比如‘ 0 ’ 是一个东西,不做区分
    jswh
        16
    jswh  
       2017-01-14 18:23:32 +08:00
    @jswh 虽然实现上有些不一样,但理解上,你就是没有键的数组理解成所有键都是'0','1', '2', '3'就好了
    iyaozhen
        17
    iyaozhen  
       2017-01-14 20:52:31 +08:00 via Android
    实际上你这样 data 是一个 map 了,不能用下标索引了。而且楼主你这实现有点挫。且不论拼 SQL 这件事。其实你 filed 应该是确定的,没必要做 key 。 data 存成[[1,a,x] ,[2,b,y] ,[3,c,z]]不是更好?
    CoderRunner
        18
    CoderRunner  
       2017-01-14 21:43:41 +08:00
    文档里已经解释的很详细了
    http://php.net/manual/zh/language.types.array.php
    quericy
        19
    quericy  
       2017-01-14 21:50:45 +08:00
    楼主的实现方式就不吐槽了.
    但是单论有索引的数组,还是有些方法可以取第几个元素的
    比如 array_slice , length 置为 1, 偏移量 offset 作为序号
    koodai
        20
    koodai  
    OP
       2017-01-15 00:41:12 +08:00
    @msg7086 感谢,是自己学艺不精,以前真没认真考虑过;
    @jswh 握手握手,感谢,可能跟其他语言的使用习惯有点混淆了。
    @iyaozhen 只是一个 BAE 上的 php-worker 单文件抓取工具,场景单一相对来说不想复杂化,全手工实现一个小工具而已,可能在其他环境下这做法确实很挫;另外, filed 这里确实是固定的,但是正则匹配出来的东西,就是我给出的样子,没有再做加工;

    @quericy 感觉你的方法更加复杂了,,,对于一个百十行左右完整抓取、保存的小工具来说,我喜欢简单粗暴。 如果不在乎繁复,循环解千愁,也不是一定要取索引,只是偶然遇到这个问题,感觉有点奇葩。
    koodai
        21
    koodai  
    OP
       2017-01-15 00:42:03 +08:00
    @quericy thanks !
    -----------------------
    此外 key 会有如下的强制转换:

    包含有合法整型值的字符串会被转换为整型。例如键名 "8" 实际会被储存为 8 。但是 "08" 则不会强制转换,因为其不是一个合法的十进制数值。
    浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8 。
    布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0 。
    Null 会被转换为空字符串,即键名 null 实际会被储存为 ""。
    数组和对象不能被用为键名。坚持这么做会导致警告: Illegal offset type 。
    如果在数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了。

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

    <?php
    $array = array(
    1 => "a",
    "1" => "b",
    1.5 => "c",
    true => "d",
    );
    var_dump($array);
    ?>
    以上例程会输出:

    array(1) {
    [1]=>
    string(1) "d"
    }
    上例中所有的键名都被强制转换为 1 ,则每一个新单元都会覆盖前一个的值,最后剩下的只有一个 "d"。

    PHP 数组可以同时含有 integer 和 string 类型的键名,因为 PHP 实际并不区分索引数组和关联数组。
    -----------------------------
    这些定义,感觉很神奇! ^_^
    klom303
        22
    klom303  
       2017-01-16 10:25:27 +08:00
    其实要处理数组,不一定要套 for 循环,有一些很好用的数组函数啊,比如:
    ```
    $data = array(
    'filed1' => array(1, 2, 3),
    'filed2' => array('a', 'b', 'c'),
    'filed3' => array('x', 'y', 'z'),
    );

    $result = array_map(function ($filed1, $filed2, $filed3) {
    return "('{$filed1}','{$filed2}','{$filed3}')";
    }, $data['filed1'], $data['filed2'], $data['filed3']);

    echo implode(',',$result);
    ```
    koodai
        23
    koodai  
    OP
       2017-01-16 15:11:32 +08:00
    @klom303 十万个赞!我以前对 array_map 有用过,但是没有这么用过。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5451 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 07:09 · PVG 15:09 · LAX 23:09 · JFK 02:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.