0

The goal is to pass a specific array element through custom_format().

Example: If $hierarchy = '4:0:2', then $data[4][0][2] = custom_format($data[4][0][2]).

Does anyone know how to replicate the following code without relying on eval()?

Current code:

$hierarchy = '4:0:2';
$hierarchy = str_replace(':', '][', $hierarchy);
eval("\$data[$hierarchy] = custom_format(\$data[$hierarchy]);");

Thanks in advance.

Matt
  • 3,778
  • 9
  • 35
  • 36
  • See the code from [this answer](http://stackoverflow.com/a/10781524/1396314) to retrieve the value from multidimensional array. It uses dot-separated keys (e.g: `4.0.2`), but you can easily change it to `:`. – flowfree Jun 27 '12 at 15:02
  • That example will only retrieve a value. I'm trying to actually replace a specific value within a multidimensional array. – Matt Jun 27 '12 at 15:07
  • Thanks for the help guys. It looks like this thread also has some relevant answers: http://stackoverflow.com/questions/7851590/array-set-value-using-dot-notation – Matt Jun 27 '12 at 16:14

2 Answers2

2

An overly verbose yet elegant option is the following:

class MyArray implements ArrayAccess {
    public function offsetExists($offset) {
        if(!is_array($offset))
            $offset = explode(':', $value);
        $key = array_shift($offset);
        if($key !== NULL) {
            if($this->$key InstanceOf MyArray) {
                return(isset($this->$key[$offset]));
            }
        }
    }
    public function offsetGet($offset) {
        if(!is_array($offset))
            $offset = explode(':', $value);
        $key = array_shift($offset);
        if($key !== NULL) {
            if($this->$key InstanceOf MyArray) {
                return($this->$key[$offset]);
            }
        }
    }
    public function offsetSet($offset, $value) {
        if(!is_array($offset))
            $offset = explode(':', $value);
        $key = array_shift($offset);
        if($key !== NULL) {
            if(!($this->$key InstanceOf MyArray)) {
                $this->$key = new MyArray;
            }
            $this->$key[$offset] = $value;
        }
    }
    public function offsetUnset($offset) {
        if(!is_array($offset))
            $offset = explode(':', $value);
        $key = array_shift($offset);
        if($key !== NULL) {
            if($this->$key InstanceOf MyArray) {
                return(unset($this->$key[$offset]));
            }
            if(count($offset) == 0) {
                return(unset($this->$key));
            }
        }
    }
}

This does imply using MyArray everywhere you need this kind of array behaviour and perhaps creating a static method that recursively converts arrays and they array children into MyArray objects so that they will respond consistently to this behavior.

One concrete example is the need to change the offsetGet method, to check if $value is an array then to use the conversion function to convert it to a MyArray if you want to access its elements.

Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51
0

How about something like this:

<?php
$hierarchy = '4:0:2';
list($a,$b,$c) = explode(':',$hierarchy);
echo $data[$a][$b][$c];
?>
Jamie Bicknell
  • 2,306
  • 17
  • 35
  • No, sorry I didn't clarify -- assume that $data can have more than 3 dimensions. – Matt Jun 27 '12 at 15:03
  • @Jamie actually assume that $data can have any number of dimensions. – Mihai Stancu Jun 27 '12 at 15:19
  • In that case, I can't see any other way than to loop through each of your elements and do an IF on each one until all the keys match up, then do you replace when they all match. Not exactly efficient, but in all honesty, what are you going to do with the array if you don't know how many depths it has? – Jamie Bicknell Jun 27 '12 at 15:25
  • We know exactly what depth we need by the $hierarchy string. – Matt Jun 27 '12 at 15:35
  • @Matt What Jaimie meant was if we don't know the exact depth at **compile time** as opposed to **run time**. – Mihai Stancu Jun 27 '12 at 15:36
  • Of course I know PHP isn't compiled, but the wording **compile time** takes the meaning of code that is fixed, and analyzable before running it. Eval is an example of constructing code at **run time**. Jaimie said it couldn't be done using only code written by you without using generated code. I disagree as per my example, looping and recursion are two approaches that can solve this issue. – Mihai Stancu Jun 27 '12 at 15:39