Any PHP function that will strip properties of an object that are null?
Asked Answered
G

7

26

I am returning a json_encode() of an array of objects pulled from an ORM. It includes lots of properties with a null value. What is the neatest way to remove these properties that are null? I guess I could iterate over the properties, look if they are null and then unset() that property, but surely there must be a more elegant way?

Gasket answered 4/12, 2010 at 6:4 Comment(0)
B
42

Try this; it will only work on a simple object, but if it's coming from an ORM it should be simple enough.

// Strips any false-y values
$object = (object) array_filter((array) $object);

Thanks to Gordon's answer to another question yesterday for giving me the idea.

This works by

  • converting the object to an associative array, where object properties are the keys and their values are the array values
  • using array_filter with default arguments to remove array entries with a false (e.g. empty, or null) values
  • converting the new array back to a simple object

Note that this will remove all properties with empty values, including empty strings, false boolean values and 0s, not just nulls; you can change the array_filter call if you want to keep those and only remote those that are exactly null.

// Strips only null values
$object = (object) array_filter((array) $object, function ($val) {
    return !is_null($val);
});
Bonhomie answered 4/12, 2010 at 6:16 Comment(1)
Added explanation, with a couple of caveats - you'll also lose properties with values like '' and 0. The array_filter argument can be modified if you'd like to keep those.Bonhomie
A
9

I'm going to add to the response given by El Yobo because that will only work if you have a 1 dimensional object or array. If there is any array or object nesting then in order to get the accepted solution to work you must create some sort of recursive array filter. Not good.

The best solution my colleague and I came up with was to actually perform a regular expression on the JSON string before it was returned from the server.

$json = json_encode($complexObject);
echo preg_replace('/,\s*"[^"]+":null|"[^"]+":null,?/', '', $json);

The regular expression will remove all places in the string of the form ,"key":null including any whitespace between the leading comma and the start of the key. It will also match "key":null, afterwards to make sure that no null values were found at the beginning of a JSON object.

This obviously isn't the most ideal situation but it will effectively remove null entries without having to develop some kind of recursive array filter.

Annia answered 11/4, 2013 at 18:1 Comment(1)
json_encode() to hack at the payload with regex is not generally a good idea. Private properties will be lost and if there are escaped double quotes in a property name (key), then this regex doesn't look equipped to handle that. json_encode an array of objects with private propertiesNomen
B
3

Despite the name you can also use array_walk with a closure:

// Setup
$obj = (object) array('foo' => NULL, 'bar' => 'baz');

// equivalent to array_filter
array_walk($obj, function($v,$k) use ($obj) {
    if(empty($v)) unset($obj->$k);
});

// output
print_r($obj);

Output

stdClass Object
(
    [foo] => bar
)
Bedding answered 4/12, 2010 at 10:0 Comment(4)
How this can be recursive if there is nested objects?Shawnshawna
@Shawnshawna there is also array_walk_recursiveBedding
do note that this will delete booleans. If you need bools , use this line in the code by @Bedding : if( empty( $v ) && !is_bool( $v ) ) unset( $res->$k );Amenable
Using array_walk_recursive with the above approach is not a solution for nested objects, since casting an object to an array only casts the top level and leaves nested objects intact.Shope
E
1

There's no standard function to remove null-valued properties. Writing one of your own isn't inelegant, if you write one elegantly.

Excision answered 4/12, 2010 at 6:9 Comment(1)
Which is effectively what every other answer here has done! :-)Shope
P
1

I made this function that solves my problem: clean null 'object properties' and 'array properties' inside an object. Also, you can have many 'levels' of objects/arrays inside of an object:

function cleanNullsOfObject(&$object) {
    foreach ($object as $property => &$value) {
        if (is_object($value)) {
            cleanNullsOfObject($value);
            if (empty(get_object_vars($value))) {
                unset($object->$property);
            }
        }
        if (is_array($value) && is_object($value[0])) {
            foreach ($value as $val) {
                cleanNullsOfObject($val);
            }
        }
        if (is_null($value) || (is_array($value) && empty($value))) {
            unset($object->$property);
        }
    }
}
//test
$object = new stdClass();
$object->property = "qwe";
$object->nullProperty = null;
$propertyObject = new stdClass();
$propertyObject->property = "asd";
$propertyObject->nullProperty = null;
$object->propertyObject = $propertyObject;
var_dump($object);
echo "<br>";
echo "<br>";
cleanNullsOfObject($object);
var_dump($object);
Pointing answered 30/1, 2019 at 23:47 Comment(1)
Thanks! I had an old php 5.2 app that was leaking memory, and I used this to clean it up.. really helped!Koerlin
E
0

Building off of @Gordon 's answer, a couple of adjustments would be needed to make that work, but you can also use array_walk_recursive instead. The reference is required or otherwise any changes you make to the object won't apply to the scope outside of the Closure.

IE:

$someObject = (array)$someObject;
array_walk_recursive($someObject, function($v,$k) use (&$someObject) {
    if($someObject[$k] == null) {
        unset($someObject[$k]);
    }
});

$someObject = (object)$someObject;

var_dump($someObject);
Extemporize answered 29/3, 2016 at 17:46 Comment(1)
Not sure why array_walk_recursive is any better than array_walk for this purpose - the result is the same. It also suggests that this solution would work for multi-level objects, which it does not and so is misleading. Try this input: $someObject = (object)['a'=>1, 'b'=>2, 'c'=>null, 'd'=>(object)['da'=>3, 'db'=>null]]; Only c is removed in the output, leaving db intact.Shope
S
0

Here is an implementation that should cope with about any combination of nested objects, arrays and associative arrays. To be clear, this creates a 'de-nulled' copy of the original structure, rather than stripping back the original object or array in place.

function filter_nulls($input) {
    $result = new stdClass();
    foreach ($input as $k => $v) {
        if (!is_null($v)) {
            $result->$k = is_scalar($v) ? $v : filter_nulls($v);
        }
    }
    return is_array($input) ? (array) $result : $result;
}

Test:

$someObject = (object) [
    'a' => 1, 
    'b' => 2, 
    'c' => null, 
    'd' => (object) ['da' => 3, 'db' => null], 
    'e' => [null], 
    'f' => ['fa' => (object) ['faa' => 2, 'fab' => null], 'fb' => null]
];

$filteredObject = filter_nulls($someObject);
var_dump($filteredObject);

Outputs:

object(stdClass)#2 (5) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
  ["d"]=>
  object(stdClass)#1 (1) {
    ["da"]=>
    int(3)
  }
  ["e"]=>
  array(0) {
  }
  ["f"]=>
  array(1) {
    ["fa"]=>
    object(stdClass)#9 (1) {
      ["faa"]=>
      int(2)
    }
  }
}
Shope answered 5/10, 2023 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.