【问题标题】:Merging two complex objects in PHP在 PHP 中合并两个复杂对象
【发布时间】:2012-02-11 16:24:59
【问题描述】:

我有两个从 JSON 转换而来的数据对象。两者都非常复杂,我想以类似于 jQuery 如何使用扩展合并两个对象的方式合并它们。

例子

JSON 1:

{
    ...
    "blah":
    {
        "params":
        {
            "foo":
            {
                "default": "bar",
                "misc": "0",
                ...
            },
            ...
        },
        ...
    },
    ...
}

JSON 2:

{
    ...
    "blah":
    {
        "params":
        {
            "foo":
            {
                "value": "val",
                "misc": "1",
                ...
            },
            ...
        },
        ...
    },
    ...
}

合并到

{
    ...
    "blah":
    {
        "params":
        {
            "foo":
            {
                "default": "bar",
                "value": "val",
                "misc": "1",
                ...
            },
            ...
        },
        ...
    },
    ...
}

使用 PHP 对象处理此问题的最佳方法是什么。

【问题讨论】:

标签: php json


【解决方案1】:

正如@infinum 的仅链接答案所暗示的,array_replace_recursive() 是完成此任务的正确本机工具。

我不确定为什么 OP 接受 @meouw 的回答,因为 array_merge_recursive() 是一个不恰当的调用,并且当 php 已经有一个本地调用时,滚动你自己的自定义递归脚本是不必要的劳动。

由于绿色勾号以及对部分不正确且未达到最佳创可贴答案的众多赞成票,此页面很可能会误导研究人员,并代表一个没有吸引力的候选人来关闭未来的重复问题。

脚本只需要将json字符串解码成数组,调用递归函数,然后重新编码得到的数组。

这里完整演示了如何准备 json 字符串并使用array_replace_recursive()

代码:(Demo)

$json1 = '{"blah":{"params":{"foo":{"default":"bar","misc":"0"}}}}';
$json2 = '{"blah":{"params":{"foo":{"value":"val","misc":"1"}}}}';
echo json_encode(
    array_replace_recursive(
        json_decode($json1, true),
        json_decode($json2, true)
    ),
    JSON_PRETTY_PRINT
);

输出:

{
    "blah": {
        "params": {
            "foo": {
                "default": "bar",
                "misc": "1",
                "value": "val"
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    将每个 JSON 字符串解码为关联数组,合并结果并重新编码

    $a1 = json_decode( $json1, true );
    $a2 = json_decode( $json2, true );
    
    $res = array_merge_recursive( $a1, $a2 );
    
    $resJson = json_encode( $res );
    

    更新: 如果您有特定的合并要求,那么您需要编写自己的合并函数。 我在下面写了一个,它可以满足您在问题中所述的要求。 如果您有其他未提及的要求,您可能需要对其进行调整。

    <?php
    
    $json1 = '
    {
        "blah":
        {
            "params":
            {
                "foo":
                {
                    "default": "bar",
                    "misc": "0"
                }
            },
            "lost":
            {
                "one": "hat",
                "two": "cat"
            }
        }
    }';
    
    $json2 = '
    {
        "blah":
        {
            "lost": "gone",
            "params":
            {
                "foo":
                {
                    "value": "val",
                    "misc": "1"
                }
            }
        },
        "num_array": [12, 52, 38]
    }';
    
    
    $a1 = json_decode( $json1, true );
    $a2 = json_decode( $json2, true );
    
    
    /*
     * Recursive function that merges two associative arrays
     * - Unlike array_merge_recursive, a differing value for a key
     *   overwrites that key rather than creating an array with both values
     * - A scalar value will overwrite an array value
     */
    function my_merge( $arr1, $arr2 )
    {
        $keys = array_keys( $arr2 );
        foreach( $keys as $key ) {
            if( isset( $arr1[$key] ) 
                && is_array( $arr1[$key] ) 
                && is_array( $arr2[$key] ) 
            ) {
                $arr1[$key] = my_merge( $arr1[$key], $arr2[$key] );
            } else {
                $arr1[$key] = $arr2[$key];
            }
        }
        return $arr1;
    }
    
    
    $a3 = my_merge( $a1, $a2);
    $json3 = json_encode( $a3 );
    echo( $json3 );
    
    /*
    {
        "blah":
        {
            "params":
            {
                "foo":
                {
                    "default": "bar",
                    "misc":    "1",
                    "value":   "val"
                }
            },
            "lost": "gone"
        },
        "num_array": [12,52,38]
    }
    */
    

    【讨论】:

    • 这几乎可以做到,但它没有覆盖现有的键,而是采用两个值并创建一个包含这两个值的数组。有没有办法改变这种行为?
    • 我已经更新了我的答案 - 合并是专门为您的要求而构建的
    • Sweet,这与我最终所做的非常接近。谢谢!
    【解决方案3】:

    使用array-replace-recursive()http://www.php.net/manual/en/function.array-replace-recursive.php
    它完全符合您的要求。

    【讨论】:

    • 欢迎来到 StackOverflow!你能提供一个代码示例吗?此处不欢迎仅提供链接的答案。
    • 你好@JanDvorak 链接下有足够多的代码示例。如果您觉得您仍然需要更多,请提供更好的答案。
    • 抱歉,这个答案完全是错误的——函数是针对数组的——而不是针对对象的。问题中的数据包含对象。当然,您可以将对象转换为数组或其他方式,但结果将不再具有相同的对象结构。
    • 就是这样!!谢谢!
    【解决方案4】:

    对@meouw 的代码(上图)进行了一些改进,允许在对象中合并索引数组。

    $a = '{ "things": ["abc"], "apple":"pear" }';
    $b = '{ "things": ["123"] }';
    
    $a1 = json_decode( $a, true );
    $b1 = json_decode( $b, true );
    
    echo json_encode(deep_merge($a1,$b1));
    // output: {"things":["abc","123"],"apple":"pear"}
    
    function deep_merge( $arr1, $arr2 )
    {
        $keys = array_keys( $arr2 );
        foreach( $keys as $key ) {
            if (isset($arr1[$key]) && is_numeric($key) ) {
                array_push($arr1,$arr2[$key]);
            }
            else if( isset($arr1[$key]) && is_array($arr1[$key]) && is_array($arr2[$key])) {
                $arr1[$key] = deep_merge( (array)$arr1[$key],(array) $arr2[$key] );
            } else {
                $arr1[$key] = $arr2[$key];
            }
        }
        return $arr1;
    }
    

    否则,输出将是{"things":["123"],"apple":"pear"}

    Example

    【讨论】:

      猜你喜欢
      • 2019-08-27
      • 2014-09-12
      • 1970-01-01
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-26
      相关资源
      最近更新 更多