【问题标题】:Is there something like keypath in an associative array in PHP?PHP中的关联数组中是否有类似keypath的东西?
【发布时间】:2013-04-29 15:26:05
【问题描述】:

我想像这样剖析一个数组:

[
    "ID",
    "UUID",
    "pushNotifications.sent",
    "campaigns.boundDate",
    "campaigns.endDate",
    "campaigns.pushMessages.sentDate",
    "pushNotifications.tapped"
]

转成这样的格式:

{
    "ID" : 1,
    "UUID" : 1,
    "pushNotifications" : 
        {
            "sent" : 1,
            "tapped" : 1
        },
    "campaigns" :
        {
            "boundDate" : 1,
            "endDate" : 1,
            "pushMessages" :
                {
                    "endDate" : 1
                }  
        }
}

如果我能以类似键路径的方式在关联数组上设置一个值,那就太好了:

//To achieve this:
$dissected['campaigns']['pushMessages']['sentDate'] = 1;

//By something like this:
$keypath = 'campaigns.pushMessages.sentDate';
$dissected{$keypath} = 1;

如何在 PHP 中做到这一点?

【问题讨论】:

  • 最上面的代码是字符串吗?
  • 是的。字符串数组(实际上是键路径数组)。
  • 拥有像 setValueForKeyPath($array, 1, 'campaigns.pushMessages.sentDate'); 之类的函数;

标签: php key associative-array


【解决方案1】:
function keyset(&$arr, $keypath, $value = NULL)
{
   $keys = explode('.', $keypath);
   $current = &$arr;
   while(count($keys))
   {
      $key = array_shift($keys);
      if(!isset($current[$key]) && count($keys))
      {
         $current[$key] = array();
      }
      if(count($keys))
      {
         $current = &$current[$key];
      }
   }
   $current[$key] = $value;
}

function keyget($arr, $keypath)
{
   $keys = explode('.', $keypath);
   $current = $arr;
   foreach($keys as $key)
   {
      if(!isset($current[$key]))
      {
         return NULL;
      }
      $current = $current[$key];
   }
   return $current;
}

//Testing code:
$r = array();
header('content-type: text/plain; charset-utf8');
keyset($r, 'this.is.path', 39);
echo keyget($r, 'this.is.path');
var_dump($r);

有点粗糙,我不能保证它的功能是 100%。

编辑:起初你很想尝试使用可变变量,但我过去曾尝试过,但它不起作用,所以你必须使用函数来做到这一点。这适用于一些有限的测试。 (我刚刚添加了一个小的编辑来删除不必要的数组分配。)

【讨论】:

    【解决方案2】:

    你可以使用:

    $array = [
            "ID",
            "UUID",
            "pushNotifications.sent",
            "campaigns.boundDate",
            "campaigns.endDate",
            "campaigns.pushMessages.sentDate",
            "pushNotifications.tapped"
    ];
    
    // Build Data
    $data = array();
    foreach($array as $v) {
        setValue($data, $v, 1);
    }
    
    // Get Value
    echo getValue($data, "campaigns.pushMessages.sentDate"); // output 1
    

    使用的功能

    function setValue(array &$data, $path, $value) {
        $temp = &$data;
        foreach(explode(".", $path) as $key) {
            $temp = &$temp[$key];
        }
        $temp = $value;
    }
    
    function getValue($data, $path) {
        $temp = $data;
        foreach(explode(".", $path) as $ndx) {
            $temp = isset($temp[$ndx]) ? $temp[$ndx] : null;
        }
        return $temp;
    }
    

    【讨论】:

    • 这看起来真的很紧凑。
    • 啊,现在我明白了。 :D 用指针进入数组,然后在没有更深的时候设置。不错的解决方案,我几乎找不到这么简单的解决方案。
    • 您可能还想考虑 SuperVariable 中的示例 8,它支持对象,Implementing MongoDB-like Query expression object evaluation 以其他灵活的方式使用数组
    【解决方案3】:

    与此同时,我想出了(另一个)解决方案:

    private function setValueForKeyPath(&$array, $value, $keyPath)
    {
        $keys = explode(".", $keyPath, 2);
        $firstKey = $keys[0];
        $remainingKeys = (count($keys) == 2) ? $keys[1] : null;
        $isLeaf = ($remainingKeys == null);
    
        if ($isLeaf)
            $array[$firstKey] = $value;
        else
            $this->setValueForKeyPath($array[$firstKey], $value, $remainingKeys);
    }
    

    对不起,“长”的命名,我来自 Objective-C 世界。 :) 所以在每个 keyPath 上调用它,它实际上给了我输出:

    fields
    Array
    (
        [0] => ID
        [1] => UUID
        [2] => pushNotifications.sent
        [3] => campaigns.boundDate
        [4] => campaigns.endDate
        [5] => campaigns.pushMessages.endDate
        [6] => pushNotifications.tapped
    )
    dissectedFields
    Array
    (
        [ID] => 1
        [UUID] => 1
        [pushNotifications] => Array
            (
                [sent] => 1
                [tapped] => 1
            )
    
        [campaigns] => Array
            (
                [boundDate] => 1
                [endDate] => 1
                [pushMessages] => Array
                    (
                        [endDate] => 1
                    )
    
            )
    
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      • 2016-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      相关资源
      最近更新 更多