arcanine
arcanine

Reputation: 1953

PHP how to delete deep keys programmatically

Imagine you have a deep array like this:

<?php 
$array = ['hello' => ['deep' => 'treasure']];

Then you had an array of the keys to access the string 'treasure'

['hello', 'deep'];

How do you delete the string treasure if you did not know the depth of the array till run time

Edit:

My apologises I've definitely not provided enough information for what I'm looking to achieve

Here is some code I've come up with which does what I need but uses unsafe eval (keep in mind the target destination could be an array so array_walk_recursive won't work)

function iterator_keys($iterator, $outer_data) {
  $keys = array();
  for ($i = 0; $i < $iterator->getDepth() + 1; $i++) {
    $sub_iterator = $iterator->getSubIterator($i);
    $keys[$i] = ($i == 0 && is_object($outer_data)
      || $i > 0 && is_object($last_iterator->current())) ?
    '->{"' . $sub_iterator->key() . '"}' :
    '["' . $sub_iterator->key() . '"]';
    $last_iterator = $sub_iterator;
  }
  return $keys;
}
function recursive_filter($data, callable $selector_function, $iterator = NULL) {
  $iterator = $iterator ?? new RecursiveIteratorIterator(
    new RecursiveArrayIterator($data),
    RecursiveIteratorIterator::CHILD_FIRST
  );
  foreach ($iterator as $key => $value) {
    if ($selector_function($value, $key, $iterator)) {
      eval('unset($data' . implode('', iterator_keys($iterator, $data)) . ');');
    }
  }
  return $data;
}

The intention is to have a deep data structure a function that evalutes each node and if it matches a condition then remove it from the data structure in place, if this can be done without eval that would be amazing but so far I think PHP can't programmatically delete something that is more than one level deep

Upvotes: 1

Views: 263

Answers (3)

AbraCadaver
AbraCadaver

Reputation: 78994

This will set the target array element to null. Optionally you could use '':

$array = ['hello' => ['deep' => 'treasure']];
$path  = ['hello', 'deep'];

$temp = &$array;

foreach($path as $key) {
    $temp =& $temp[$key];
}
$temp = null;

print_r($array);

Yields:

Array
(
    [hello] => Array
        (
            [deep] =>
        )

)

Upvotes: 0

wazelin
wazelin

Reputation: 751

Well you can try this really quick and dirty way that uses eval to achieve your goal:

$array = ['hello' => ['deep' => 'treasure']];
$keys = ['hello', 'deep'];

$expression = 'unset($array[\'' . implode('\'][\'', $keys) . '\']);';
eval($expression);

But maybe you can tell us more about your development and we can help you reorganize it somehow to avoid this problem at all.

Upvotes: 0

Ricky
Ricky

Reputation: 1571

Hello I think what you want is somethings like this

<?php    
$array = ['hello' => ['deep' => ['deep1' => 'treasure']]];
$keys = ["hello", "deep", "deep1"];

function remove_recursive(&$array, $keys, $level = 0)
{
    if ($level >= count($keys)) {
        return $array;
    }
    if (isset($array[$keys[$level]]) && $level == count($keys) - 1) {
        unset($array[$keys[$level]]);
    } elseif (isset($array[$keys[$level]])) {
        $array[$keys[$level]] = remove_recursive($array[$keys[$level]], $keys, $level + 1);
    }

    return $array;
}

var_dump(remove_recursive($array, $keys));

Upvotes: 1

Related Questions