Comparing two PHP objects - PHP and OBJECTS - php

I have two objects like this.
$array1
stdClass Object (
[BellId] => 2
[BellCode] => BP001
[BellDescription] => SPI SPEED ABNORMAL,CHK BELT
[ControllerId] => 3
[CreatedBy] => 1
[CreatedOn] => 2016-08-19 15:09:25
[ModifiedBy] =>
[ModifiedOn] =>
)
$array2
stdClass Object (
[BellId] => 1
[BellCode] => BP002
[BellDescription] => MCB TRIPPED,CHK MTR SHORT,O/L.
[ControllerId] => 3
[CreatedBy] => 1
[CreatedOn] => 2016-08-19 15:09:25
[ModifiedBy] =>
[ModifiedOn] =>
)
I need to compare this object and get the difference in these two objects only.
I have checked the below links but no use.
Comparing two stdClass Objects
Comparing 2 objects PHP
My Sample code is as follows
function recursive_array_diff($a1, $a2) {
$r = array();
foreach ($a1 as $k => $v) {
if (array_key_exists($k, $a2)) {
if (is_array($v)) {
$rad = recursive_array_diff($v, $a2[$k]);
if (count($rad)) {
$r[$k] = $rad;
}
} else {
if ($v != $a2[$k]) {
$r[$k] = $v;
}
}
} else {
$r[$k] = $v;
}
}
return $r;
}
Can someone help me with the code.

Use array_diff_assoc(); e.g:
<?php
$foo = new stdClass();
$foo->BellId = 1;
$foo->BellDescription = 'foo';
$foo->CreatedBy = 1;
$bar = new stdClass();
$bar->BellId = 2;
$bar->BellDescription = 'bar';
$bar->CreatedBy = 1;
$diff = array_diff_assoc((array) $foo, (array) $bar);
print_r($diff);
array_diff_assoc performs a diff of arrays with additional index check. In your case this is required because you want to perform a key/value diff, not a diff on the values alone.
The above code yields:
Array
(
[BellId] => 1
[BellDescription] => foo
)
Note: you can transparently cast an instance of stdClass() to an array and vice versa:
$arr = ['id' => 1];
$obj = (object) $arr;
$arr = (array) $obj;
// etc.
Hope this helps :)

First convert both objects to arrays:
$arrayA = (array)$objectA;
$arrayB = (array)$objectB;
then just use array_diff to get the difference between arrays
$difference = array_diff($arrayA, $arrayB);
This will return an array containing keys from the first array ($arrayA) and their value, which gives an indication as to what fields are different between the two objects
foreach($difference as $key => $diff) {
echo $objectA->$key;
echo $objectB->$key;
// the above two values will be different
}
Note: array_diff can be used if you know the order of fields in both objects are the same, however it's probably best to use array_diff_assoc here, as this offers an additional index check.

With array_udiff_assoc you can compare the items as you like using a callback. Of course, you need to cast the objects to arrays:
$d = array_udiff_assoc((array)$array1, (array)$array2, function ($x, $y) {
if (! (is_scalar($x) && is_scalar($y))) {
trigger_error("skipping non-scalar members!", E_USER_WARNING);
// you might want to handle this in the app-specific way
}
if (is_numeric($x) && is_numeric($y))
return $x - $y;
return strcmp($x, $y);
});
var_dump($d);
where $x and $y are the items from the arrays being compared.
Sample output
array(3) {
["BellId"]=>
int(2)
["BellCode"]=>
string(5) "BP001"
["BellDescription"]=>
string(27) "SPI SPEED ABNORMAL,CHK BELT"
}
This is a very flexible way. You can put your own comparison logic into the callback. For instance, you might want to compare instances of classes:
static $date_fmt = 'YmdHis';
if ($x instanceof DateTime)
$x = $x->format($date_fmt);
if ($y instanceof DateTime)
$y = $y->format($date_fmt);

Related

Sum values from two objects where properties are the same

How can I merge two objects and sum the values of matching properties? I am hoping for a built in function in PHP, otherwise I am seeking an easy way of doing it.
See code under, where I have $objectA and $objectB which I want to become $obj_merged.
$objectA = (object) [];
$objectA->a = 1;
$objectA->b = 1;
$objectA->d = 1;
$objectB = (object) [];
$objectB->a = 2;
$objectB->b = 2;
$objectB->d = 2;
$obj_merged = (object) [
'a' => 3,
'b' => 3,
'd' => 3
];
What you want to achieve is a sum of the properties. A merge would overwrite the values. There is no built-in PHP function to do this with objects.
But you can use a simple helper function where you could put in as many objects as you like to sum up the public properties.
function sumObjects(...$objects): object
{
$result = [];
foreach($objects as $object) {
foreach (get_object_vars($object) as $key => $value) {
isset($result[$key]) ? $result[$key] += $value : $result[$key] = $value;
}
}
return (object)$result;
}
$sumObject = sumObjects($objectA, $objectB);
stdClass Object
(
[a] => 3
[b] => 3
[d] => 3
)
There is no need to loop over both objects. Save the first object to the result object, then loop over the second object and add the related values between the current property and the result object. The null coalescing operator is used to add zero when there is no corresponding property in the result object.
Code: (Demo)
$result = $objectA;
foreach ($objectB as $prop => $value) {
$result->$prop = ($result->$prop ?? 0) + $value;
}
var_export($result);
If the properties between the two objects are guaranteed to be identical, then there is no need to coalesce with zero. Demo
$result = $objectA;
foreach ($objectB as $prop => $value) {
$result->$prop += $value;
}

Removing object from array; how to avoid nulls

I have an array that is a object which I carry in session lifeFleetSelectedTrucksList
I also have objects of class fleetUnit
class fleetUnit {
public $idgps_unit = null;
public $serial = null;
}
class lifeFleetSelectedTrucksList {
public $arrayList = array();
}
$listOfTrucks = new lifeFleetSelectedTrucksList(); //this is the array that I carry in session
if (!isset($_SESSION['lifeFleetSelectedTrucksList'])) {
$_SESSION['lifeFleetSelectedTrucksList'] == null; //null the session and add new list to it.
} else {
$listOfTrucks = $_SESSION['lifeFleetSelectedTrucksList'];
}
I use this to remove element from array:
$listOfTrucks = removeElement($listOfTrucks, $serial);
And this is my function that removes the element and returns the array without the element:
function removeElement($listOfTrucks, $remove) {
for ($i = 0; $i < count($listOfTrucks->arrayList); $i++) {
$unit = new fleetUnit();
$unit = $listOfTrucks->arrayList[$i];
if ($unit->serial == $remove) {
unset($listOfTrucks->arrayList[$i]);
break;
} elseif ($unit->serial == '') {
unset($listOfTrucks->arrayList[$i]);
}
}
return $listOfTrucks;
}
Well, it works- element gets removed, but I have array that has bunch of null vaues instead. How do I return the array that contains no null elements? Seems that I am not suing something right.
I think what you mean is that the array keys are not continuous anymore. An array does not have "null values" in PHP, unless you set a value to null.
$array = array('foo', 'bar', 'baz');
// array(0 => 'foo', 1 => 'bar', 2 => 'baz');
unset($array[1]);
// array(0 => 'foo', 2 => 'baz');
Two approaches to this:
Loop over the array using foreach, not a "manual" for loop, then it won't matter what the keys are.
Reset the keys with array_values.
Also, removing trucks from the list should really be a method of $listOfTrucks, like $listOfTrucks->remove($remove). You're already using objects, use them to their full potential!
You can use array_filter
<?php
$entry = array(
0 => 'foo',
1 => false,
2 => -1,
3 => null,
4 => ''
);
print_r(array_filter($entry));
?>
output:
Array
(
[0] => foo
[2] => -1
)

How to find object in php array and delete it?

Here is print_r output of my array:
Array
(
[0] => stdClass Object
(
[itemId] => 560639000019
[name] => Item no1
[code] => 00001
[qty] => 5
[id] => 2
)
[1] => stdClass Object
(
[itemId] => 470639763471
[name] => Second item
[code] => 76347
[qty] => 9
[id] => 4
)
[2] => stdClass Object
(
[itemId] => 56939399632
[name] => Item no 3
[code] => 39963
[qty] => 6
[id] => 7
)
)
How can I find index of object with [id] => 4 in order to remove it from array?
$found = false;
foreach($values as $key => $value) {
if ($value->id == 4) {
$found = true;
break;
}
}
if ($found) unset($values[$key]);
This is considered to be faster then any other solution since we only iterate the array to until we find the object we want to remove.
Note: You should not remove an element of an array while iterating so we do it afterwards here.
foreach($parentObj AS $key=>$element){
if ($element->id == THE_ID_YOU_ARE_LOOKING_FOR){
echo "Gottcha! The index is - ". $key;
}
}
$parentObj is obviously your root array - the one that holds all the others.
We use the foreach loop to iterate over each item and then test it's id property against what ever value you desire. Once we have that - the $key that we are on is the index you are looking for.
use array_search:
$a = new stdClass;
$b = new stdClass;
$a->id = 1;
$b->id = 2;
$arr = array($a, $b);
$index = array_search($b, $arr);
echo $index;
// prints out 1
try this
foreach($array AS $key=>$object){
if($object['id'] == 4){
$key_in_array = $key;
}
}
// chop it from the original array
array_slice($array, $key_in_array, 1);
Another way to achieve the result is to use array_filter.
$array = array(
(object)array('id' => 5),
(object)array('id' => 4),
(object)array('id' => 3)
);
$array = array_filter($array, function($item) {
return $item->id != 4;
});
print_r($array);
Here's my solution. Given, it is a bit hackish, but it will get the job done.
search(array $items, mixed $id[, &$key]);
Returns the item that was found by $id. If you add the variable $key it will give you the key of the item found.
function search($items, $id, &$key = null) {
foreach( $items as $item ) {
if( $item->id == $id ) {
$key = key($item);
return $item;
break;
}
}
return null;
}
Usage
$item = search($items, 4, $key);
unset($items[$key]);
Note: This could be modified to allow a custom key and return multiple items that share the same value.
I've created an example so you can see it in action.
A funny alternative
$getIdUnset = function($id) use ($myArray)
{
foreach($myArray as $key => $obj) {
if ($obj->id == $id) {
return $key;
}
}
return false;
};
if ($unset = $getIdUnset(4)) {
unset($myArray[$unset]);
}
Currently php does not have any supported function for this yet.
So refer to Java's Vector, or jQuery's $.inArray(), it would simply be:
public function indexOf($object, array $elementData) {
$elementCount = count($elementData);
for ($i = 0 ; $i < $elementCount ; $i++){
if ($object == $elementData[$i]) {
return $i;
}
}
return -1;
}
You can save this function as a core function for later.
In my case, this my array as $array
I was confused about this problem of my project, but some answer here helped me.
array(3) {
[0]=> float(-0.12459619130796)
[1]=> float(-0.64018439966448)
[2]=> float(0)
}
Then use if condition to stop looping
foreach($array as $key => $val){
if($key == 0){ //the key is 0
echo $key; //find the key
echo $val; //get the value
}
}
I know, after so many years this could be a useless answer, but why not?
This is my personal implementation of a possible index_of using the same code as other answers but let the programmer to choose when and how the check will be done, supporting also complex checks.
if (!function_exists('index_of'))
{
/**
* #param iterable $haystack
* #param callable $callback
* #param mixed|null &$item
* #return false|int|string
*/
function index_of($haystack, $callback, &$item = null)
{
foreach($haystack as $_key => $_item) {
if ($callback($_item, $_key) === true) {
$item = $_item;
return $_key;
}
}
return false;
}
}
foreach( $arr as $k=>&$a) {
if( $a['id'] == 4 )
unset($arr[$k]);
}

recursive function with variable number of arguments - how to pass left arguments?

I have an array like this:
$months = Array (
"may" =>
Array (
"A" => 101,
"B" => 33,
"C" => 25
),
"june" =>
Array (
"A" => 73,
"B" => 11,
"D" => 32
),
"july" =>
Array (
"A" => 45,
"C" => 12
)
);
I want to get an array like this:
Array ( ['all'] =>
Array (
[A] => 219
[B] => 44
[C] => 37
[D] => 32
)
)
I wrote a function with 2 parameters (the two arrays to join) and it worked, but I fail, when I try to make it possible to call it with more than 2 arrays. I tried to do it via recursion:
function array_merge_elements(){
$arg_list = func_get_args();
$array1 = $arg_list[0];
$array2 = $arg_list[1];
$keys = array_unique(array_merge(array_keys($array1), array_keys($array2)));
$result_array = array();
foreach($keys as $key) {
$result_array["$key"] = 0;
if(!empty($array1[$key])) {
$result_array["$key"] += $array1[$key];
}
if(!empty($array2[$key])) {
$result_array["$key"] += $array2[$key];
}
}
if(func_num_args() == 2) {
return $result_array;
} else {
unset($arg_list[0]);
unset($arg_list[1]);
return array_merge_elements($result_array, $arg_list);
}
}
The problem seems to be, that calling the function with (array1, arglist) is not the same as calling the function with (array1, array2, array3) etc.
What's wrong with just doing (demo)
foreach ($months as $month) {
foreach ($month as $letter => $value) {
if (isset($months['all'][$letter])) {
$months['all'][$letter] += $value;
} else {
$months['all'][$letter] = $value;
}
}
}
print_r($months['all']);
or - somewhat less readable due to the ternary operation (demo):
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($months));
foreach ($iterator as $letter => $value) {
isset($months['all'][$letter])
? $months['all'][$letter] += $value
: $months['all'][$letter] = $value;
}
print_r($months['all']);
If you'd split off the first two entries of your found arguments; you can use the resulting array in a call with this function: Call_user_func_array
for fellow googlers out there, here's the answer to the original question
Assume we have a function that adds two arrays together:
function array_plus($a, $b) {
foreach($b as $k => $v)
$a[$k] = (isset($a[$k]) ? $a[$k] : 0) + $v;
return $a;
}
this is how to apply this function to a set of arrays
$sum = array_reduce($months, 'array_plus', array());

PHP providing a closure to determine uniqueness of an item in an array

Quick question: is there a way to provide a closure in PHP to some equivalent function to the array_unique function so that you can specify your own comparison closure to be used when comparing two items in the array? I have an array of class instances (which may contain duplicates) and want to tell PHP to use particular logic to determine uniqueness.
PHP provides this with sorting using the usort() method - just wondering if it is also available for uniqueness checks. Thanks!
there is array_filter that you can apply a callback to each element in an array and return true/false of whether to keep that value in the returning array. Here is a comment using array_filter to remove duplicates in an array.
I couldn't find exactly what you are looking for but i thought maybe it wouldn't be too tough to write your own function...
$a = new StdClass;
$b = new StdClass;
$c = new StdClass;
$d = new StdClass;
$a->a = 1;
$b->a = 1;
$c->c = 1;
$d->c = 1;
$objects = array( $a,$b,$c,$d );
function custom_array_unique( array $objects ) {
foreach( $objects as $k =>$object ) {
foreach( $objects as $k2 => $object2 ) {
if ( $k !== $k2 && $object == $object2 ) {
unset( $objects[$k] );
}
}
}
return $objects;
}
print_r( custom_array_unique($objects));
Array
(
[1] => stdClass Object
(
[a] => 1
)
[3] => stdClass Object
(
[c] => 1
)
)
The manual page for array_unique() doesn't provide any links to a callback version, and there isn't a function in the list of links on the left called array_uunique() (which is what such a function should be called if it follows the naming convention of the other array sorting functions - but then PHP isn't very reliable when it comes to function naming conventions).
You could add this functionality yourself using a double foreach loop:
$uniqueness_fails = false;
foreach ( $myarray as $keyA => $valueA ) {
foreach ( $myarray as $keyB => $valueB ) {
if ( $keyA != $keyB and my_equality_function($valueA, $valueB) ) {
$uniqueness_fails = true;
break 2;
}
}
}

Categories