基于属性合并PHP中的对象

What I am originally trying to do is merge two objects

I have one object like this

{#23 ▼
  +"Name": "Consultation"
  +"ServiceId": "1024"
  +"Price": ".00"
}

Another object

{#362 ▼
  +"StartTime": "9:15AM"
  +"ServiceId": "1024"
}

I am looking for a way to merge these two objects based on it's ServiceId, so I get a single object like this

   {#1 ▼
      +"Name": "Consultation"
      +"ServiceId": "1024"
      +"Price": ".00"
      +"StartTime": "9:15AM"
     }

Of course, if the ServiceId between the two objects do not match, it should not merge.

Any ideas on how to solve the error?

There seems to be two parts to your question. The first part is how to merge the output of two objects returned by json_decode. The second part is how to merge them only if the ServiceId match.


Part 1

json_decode produces, by default, objects of class \StdClass. If you want merge two \StdClass objects into a third \StdClass object, you need some judicious casting:

$a = json_decode('{"Name":"Consultation", "ServiceId":"1024", "Price":".00"}');
$b = json_decode('{"StartTime": "9:15AM", "ServiceId": "1024"}');
$c = (object)array_merge((array)$a, (array)$b);
var_dump($c);

Here, $a and $b are \StdClass objects. Cast them to array, merge, then cast them back to \StdClass.

That's a bit of a round-about way to go. So, you can benefit from working with these as arrays from the get-go. json_decode takes an optional second argument, which instructs it to return an array:

$a = json_decode('{"Name":"Consultation", "ServiceId":"1024", "Price":".00"}', true);
$b = json_decode('{"StartTime": "9:15AM", "ServiceId": "1024"}', true);
$c = array_merge($a, $b);
var_dump($c);

This works in arrays the whole time. If you later want $c to be a \StdClass object, you can cast it using $c = (object)$c; as was done in the first example.

See these live on 3v4l.org.


Part 2

Presumably, you're going to need some logic that iterates or otherwise pairs these objects together. You don't mention the source, but the logic will look something like this:

if ($a->ServiceId == $b->ServiceId) {
    $c = (object)array_merge((array)$a, (array)$b)
}

If you have a list of objects, and you want to merge them all together, you can use the combinatoric array walk behavior of usort:

$merged = [];
usort($objects, function ($a, $b) use ($merged) {
    $comp = strcmp($a->ServiceId, $b->ServiceId);
    if (0 === $comp) {
        $merged[] = (object)array_merge((array)$a, (array)$b)
    }
    return $comp;
});
var_dump($merged);

This iterates through your list of objects, comparing each. If the ServiceId match, then it merges the two objects and adds it to a list of merged. This will happen for as many objects that share ServiceId as you have in your list.

The idea here is too loop through 1 array and find the (assuming 1) element in the other array that match the current one:

foreach ($array1 as $key => $item) {
    $other = array_filter($array2, function ($item2) use ($item) { 
        return $item2->ServiceId == $item->ServiceId;
    });
    if (!empty($other)) {
        $item->StartTime = current($other)->SomethingElse;
    }
}

Because you're dealing with objects merging all properties is a bit tricky.

Here's an example:

http://sandbox.onlinephpfunctions.com/code/15a9710dea77672c4ac4165044ad2c7aae4ae234