How to Recursively Unset Array Keys and Object Properties in PHP

Recently, I implemented a frontend UX that asynchronously loads data from an API. The server-side requests to the API return nested records, each with their own resource IDs, like this:

{
	"ID": 123,
	"type": "person",
	"name": "John Smith",
	"friends": [
		{
			"ID": 456,
			"type": "person",
			"name": "Jane Doe",
			"pet": {
				"ID": 975,
				"type": "cat",
				"name": "Mittens"
			}
		},
		{
			"ID": 789,
			"type": "person",
			"name": "Bob Baker",
			"pet": null
		}
	],
	"pet": {
		"ID": 791,
		"type": "fish",
		"name": "Bubbles"
	}
}

Since the frontend didn’t need these IDs, I wanted to strip them before passing the dataset back to the frontend. That’s why I wrote some functions to recursively unset fields in my multi-dimensional datasets!

Now, there are two different ways to represent maps (key-value pairs) in PHP: objects and arrays.

Sometimes SDKs will parse data into objects while other SDKs will return data as associative arrays. To cover all cases, I’ve written the following five functions that you need to recursively unset data fields.

Notice that an ampersand (&) precedes the first parameter in each of the following functions. This is how to pass variables by reference in PHP. By passing a variable by reference, the function makes direct modifications to that variable’s value rather than returning a modified copy. This makes the functions much more efficient!

Deep Unset Object Properties

Use this function when you want to only unset a specific property in every object instance. Array keys by the same name will remain.

/**
 * Unsets object properties of the given name.
 *
 * @param array|object $data An iterable object or array to modify.
 * @param string       $prop The name of the property to remove.
 */
function deep_unset_prop( array|object &$data, string $prop ) {
  if ( is_object( $data ) ) {
    unset( $data->{$prop} );
  }
  foreach ( $data as &$value ) {
    if ( is_array( $value ) || is_object( $value ) ) {
      deep_unset_prop( $value, $prop );
    }
  }
}

Example Usage

$employees = json_decode( $employees_json, false );// Employees as objects.
deep_unset_prop( $employees, 'id' );// Remove all "id" properties.
print_r( $employees );// See the result.

Deep Unset Array Keys

Use this function when you want to only unset a specific key in every associative array. Object properties by the same name will remain.

/**
 * Unsets array keys of the given name.
 *
 * @param array|object $data An iterable object or array to modify.
 * @param string       $key  The name of the array key to remove.
 */
function deep_unset_key( array|object &$data, string $key ) {
  if ( is_array( $data ) ) {
    unset( $data[ $key ] );
  }
  foreach ( $data as &$value ) {
    if ( is_array( $value ) || is_object( $value ) ) {
      deep_unset_key( $value, $key );
    }
  }
}

Example Usage

$employees = json_decode( $employees_json, true );// Employees as arrays.
deep_unset_key( $employees, 'id' );// Remove all "id" keys.
print_r( $employees );// See the result.

Deep Unset Object Properties & Array Keys

Ideally your dataset does not mingle associative arrays and objects. Otherwise, you’ll find yourself repeatedly wondering, “Ugh! Do I use -> or [] to access the fields this time?!”

For a one-size-fits-all solution, the following function is all you need!

/**
 * Unsets array keys and object properties of the given name.
 *
 * @param array|object $data  An iterable object or array to modify.
 * @param string       $field The name of the key or property to remove.
 */
function deep_unset( array|object &$data, string $field ) {
  
  if ( is_array( $data ) ) {
    unset( $data[ $field ] );
  } elseif ( is_object( $data ) ) {
    unset( $data->{$field} );
  }
  
  foreach ( $data as &$value ) {
    if ( is_array( $value ) || is_object( $value ) ) {
      deep_unset( $value, $field );
    }
  }
}

Example Usage

deep_unset( $employees, 'id' );// Remove all "id" properties and keys.
print_r( $employees );// See the result.

Deep Unset Multiple Fields

Additionally, you may want to recursively unset multiple fields at once. This function lets you specify a variable number of fields to remove altogether!

/**
 * Unsets all array keys and object properties of the given names.
 *
 * @param array|object $data   An iterable object or array to modify.
 * @param string[]     $fields The names of the keys or properties to remove.
 */
function deep_unset_all( array|object &$data, ...$fields ) {
  
  if ( is_array( $data ) ) {
    foreach ( $fields as &$f ) {
      unset( $data[ $f ] );
    }
  } elseif ( is_object( $data ) ) {
    foreach ( $fields as &$f ) {
      unset( $data->{$f} );
    }
  }
  
  foreach ( $data as &$value ) {
    if ( is_array( $value ) || is_object( $value ) ) {
      deep_unset_all( $value, ...$fields );
    }
  }
}

Example Usage

The unwanted fields may be specified sequentially like this:

deep_unset_all( $employees, 'id', 'title', 'does_not_exist' );
print_r( $employees );// See the result.

To pass an array of unwanted fields, use the spread operator to first unpack the names like this:

$fields_to_remove = [ 'id, 'title', 'does_not_exist' ];
deep_unset_all( $employees, ...$fields_to_remove );
print_r( $employees );// See the result.

Deep Unset All Foreign Fields

Okay, now sometimes you know what fields you do want and just need to throw out the rest. Here’s how to recursively unset every field except the ones you need to keep.

With this function, you can specify the exact fields you need rather than guess all the possible fields that you don’t need!

/**
 * Unsets all array keys and object properties that are not
 * of the given names.
 *
 * @param array|object $data   An iterable object or array to modify.
 * @param string[]     $fields The names of the keys or properties to keep.
 */
function deep_unset_except( array|object &$data, ...$fields ) {
  
  if ( is_array( $data ) ) {
    foreach ( $data as $key => &$_ ) {
      if ( is_string( $key ) && ! in_array( $key, $fields, true ) ) {
        unset( $data[ $key ] );
      }
    }
  } elseif ( is_object( $data ) ) {
    foreach ( $data as $prop => &$_ ) {
      if ( ! in_array( $prop, $fields, true ) ) {
        unset( $data->{$prop} );
      }
    }
  }
  
  foreach ( $data as &$value ) {
    if ( is_array( $value ) || is_object( $value ) ) {
      deep_unset_except( $value, ...$fields );
    }
  }
}

Example Usage

Same as the previous function, the fields may be specified sequentially or unpacked from an array:

$fields_to_keep = [ 'name', 'title', 'subordinates' ];
deep_unset_except( $employees, ...$fields_to_keep );
print_r( $employees );// See the result.
Michelle Blanchette

Michelle Blanchette

Full-stack web developer, specialized in WordPress and API integrations. Currently focused on building Completionist, the Asana integration WordPress plugin.