Search code examples
phparraysmultidimensional-arrayreferenceunset

PHP - Modify array member of an n'th dimension by given address


I want to create a function that accepts a path argument and returns an appropriate member of a multi-dimensional array. Let's say we ahve this:

$myContactsBook = [
    'relatives' => [
        'bob',
        'john',
    ],
    'friends' => [
        'work' => [
            'andrew',
            'eric',
        ],
        'mars' => [
            'zoopzap'
        ],
    ],
];

I'd like to be able to do several things:

  • Read
  • Edit
  • Remove/unset

Solution

  • I've spent more time than I should have scratching my stupid head at this, so I though I'd share it in case someone might ever have a similar problem. I'll be very descriptive so beginners like myself would be able to understand everything. I suppose.

    First of all, let's agree on the address format:

    readContact('path/to/target')
    

    This is simplest to use, but can be a problem if our array keys have forward slashes in them; it also cannot differentiate between numerical indices and numerical strings.

    readContacts(['path', 'to', 'target'])
    

    This is foolproof, but a bit uglier.

    If you're sure what your keys are going to look like, you can use the string address and explode it with the / delimiter or whichever one you choose. You'll end up with an arrayanyway, so I'll assume we're using an array argument for the sake of this example:

    function unsetContacts(array $address) {
        $lookup =& $myContactsBook;
        $lastKey = array_pop($address);
        foreach ($address as $key) {
            $lookup =& $lookup[$key];
        }
        // if you want to also return the value and make this getAndUnsetContacts();
        // $return = $lookup[$last_bit];
        unset($lookup[$last_bit]);
        // return $return;
    }
    

    As you can see, if we only wanted to read the array value, we could do this:

    function readContacts(array $address) {
        $lookup = $myContactsBook;
        foreach ($address as $key) {
            $lookup = $lookup[$key];
        }
        return $lookup;
    }
    

    This won't work if you want to edit the values, because if we assigned a new value to $lookup now, it would only change that variable, but not the source array ($myContactsBook). That's easy to avoid by using PHP's assign by reference;

    function editContacts(array $address, $newValue) {
        $lookup =& $myContactsBook;
        foreach ($address as $key) {
            $lookup =& $lookup[$key];
        }
        $lookup = $newValue;
        return;
    }
    

    But, like this we still cannot unset the array members. If we use the unset() construct on $lookup now, it will unset the reference, but $myContactsBook will remain untouched. We can do something like $lookup = null, but it will not remove the array key. Depending on your needs, this might notbe enough.

    What we need is, unset($myContactsBook['path']['to']['target']);. We can get as close to that as possible by doing this:

    $lookup =& $myContactsBook['path']['to'];
    unset(lookup['target']);
    

    This is essentially what the first snippet of the code does. Please let me know if there's a better solution or something is unclear.

    That is, if anyone needs help with something so simple in the first place.