数组:使用点表示法设置值?

时间:2022-10-17 22:33:41

Looking into Kohana documentation, i found this really usefull function that they use to get values from a multidimensional array using a dot notation, for example:

查看Kohana文档,我发现这个非常有用的函数,它们用于使用点表示法从多维数组中获取值,例如:

$foo = array('bar' => array('color' => 'green', 'size' => 'M'));
$value = path($foo, 'bar.color', NULL , '.');
// $value now is 'green'

Im wondering if there is a way to set the an array value in the same way:

我想知道是否有办法以相同的方式设置数组值:

set_value($foo, 'bar.color', 'black');

The only way i found to do that is re-building the array notation ($array['bar']['color']) and then set the value.. using eval.

我发现这样做的唯一方法是重新构建数组表示法($ array ['bar'] ['color'])然后使用eval设置值。

Any idea to avoid eval?

有什么想避免评估?

6 个解决方案

#1


35  

function set_val(array &$arr, $path,$val)
{
   $loc = &$arr;
   foreach(explode('.', $path) as $step)
   {
     $loc = &$loc[$step];
   }
   return $loc = $val;
}

#2


9  

Sure it's possible.

当然有可能。

The code

function set_value(&$root, $compositeKey, $value) {
    $keys = explode('.', $compositeKey);
    while(count($keys) > 1) {
        $key = array_shift($keys);
        if(!isset($root[$key])) {
            $root[$key] = array();
        }
        $root = &$root[$key];
    }

    $key = reset($keys);
    $root[$key] = $value;
}

How to use it

$foo = array();
set_value($foo, 'bar.color', 'black');
print_r($foo);

Outputs

输出

Array
(
    [bar] => Array
        (
            [color] => black
        )

)

See it in action.

看到它在行动。

#3


6  

Look at https://gist.github.com/elfet/4713488

请访问https://gist.github.com/elfet/4713488

$dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]);

$value = $dn->get('bar.baz.foo'); // $value == true

$dn->set('bar.baz.foo', false); // ['foo'=>false]

$dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]

#4


4  

That way you can set the following values ​​more than once to the same variable.

这样,您可以将多个以下值设置为同一个变量。

You can make these two ways (by static variable and reference variable):

您可以通过以下两种方式(通过静态变量和引用变量):

<?php



    function static_dot_notation($string, $value)
    {
        static $return;

        $token = strtok($string, '.');

        $ref =& $return;     

        while($token !== false)
        {  
            $ref =& $ref[$token];
            $token = strtok('.');
        }


        $ref = $value;

        return $return;
    }

    $test = static_dot_notation('A.1', 'A ONE');
    $test = static_dot_notation('A.2', 'A TWO');
    $test = static_dot_notation('B.C1', 'C ONE');
    $test = static_dot_notation('B.C2', 'C TWO');
    $test = static_dot_notation('B.C.D', 'D ONE');

    var_export($test);

    /**
        array (
          'A' => 
              array (
                1 => 'A ONE',
                2 => 'A TWO',
              ),
          'B' => 
              array (
                'C1' => 'C ONE',
                'C2' => 'C TWO',
                'C' => 
                array (
                  'D' => 'D ONE',
                ),
          ),

    */



    function reference_dot_notation($string, $value, &$array)
    {
        static $return;

        $token = strtok($string, '.');

        $ref =& $return;     

        while($token !== false)
        {  

            $ref =& $ref[$token];
            $token = strtok('.');
        }

        $ref = $value;
        $array = $return;
    }

    reference_dot_notation('person.name', 'Wallace', $test2);
    reference_dot_notation('person.lastname', 'Maxters', $test2);

    var_export($test2);

    /**
        array (
          'person' => 
          array (
            'name' => 'Wallace',
            'lastname' => 'Maxters',
          ),
        )

    */

#5


3  

I created a small class just for this!

我为此创建了一个小班级!

http://github.com/projectmeta/Stingray

http://github.com/projectmeta/Stingray

$stingray = new StingRay();

//To Get value
$stingray->get($array, 'this.that.someother'):

//To Set value
$stingray->get($array, 'this.that.someother', $newValue):

#6


0  

Updated @hair resins' answer to cater for:

更新了@hair树脂的答案,以满足:

  • When a sub-path already exists, or
  • 当子路径已经存在时,或
  • When a sub-path is not an array

    当子路径不是数组时

    function set_val(array &$arr, $path,$val)
    {
       $loc = &$arr;
       $path = explode('.', $path);
       foreach($path as $step)
       {
           if ( ! isset($loc[$step]) OR ! is_array($loc[$step]))
               $loc = &$loc[$step];
       }
       return $loc = $val;
    }
    

#1


35  

function set_val(array &$arr, $path,$val)
{
   $loc = &$arr;
   foreach(explode('.', $path) as $step)
   {
     $loc = &$loc[$step];
   }
   return $loc = $val;
}

#2


9  

Sure it's possible.

当然有可能。

The code

function set_value(&$root, $compositeKey, $value) {
    $keys = explode('.', $compositeKey);
    while(count($keys) > 1) {
        $key = array_shift($keys);
        if(!isset($root[$key])) {
            $root[$key] = array();
        }
        $root = &$root[$key];
    }

    $key = reset($keys);
    $root[$key] = $value;
}

How to use it

$foo = array();
set_value($foo, 'bar.color', 'black');
print_r($foo);

Outputs

输出

Array
(
    [bar] => Array
        (
            [color] => black
        )

)

See it in action.

看到它在行动。

#3


6  

Look at https://gist.github.com/elfet/4713488

请访问https://gist.github.com/elfet/4713488

$dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]);

$value = $dn->get('bar.baz.foo'); // $value == true

$dn->set('bar.baz.foo', false); // ['foo'=>false]

$dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]

#4


4  

That way you can set the following values ​​more than once to the same variable.

这样,您可以将多个以下值设置为同一个变量。

You can make these two ways (by static variable and reference variable):

您可以通过以下两种方式(通过静态变量和引用变量):

<?php



    function static_dot_notation($string, $value)
    {
        static $return;

        $token = strtok($string, '.');

        $ref =& $return;     

        while($token !== false)
        {  
            $ref =& $ref[$token];
            $token = strtok('.');
        }


        $ref = $value;

        return $return;
    }

    $test = static_dot_notation('A.1', 'A ONE');
    $test = static_dot_notation('A.2', 'A TWO');
    $test = static_dot_notation('B.C1', 'C ONE');
    $test = static_dot_notation('B.C2', 'C TWO');
    $test = static_dot_notation('B.C.D', 'D ONE');

    var_export($test);

    /**
        array (
          'A' => 
              array (
                1 => 'A ONE',
                2 => 'A TWO',
              ),
          'B' => 
              array (
                'C1' => 'C ONE',
                'C2' => 'C TWO',
                'C' => 
                array (
                  'D' => 'D ONE',
                ),
          ),

    */



    function reference_dot_notation($string, $value, &$array)
    {
        static $return;

        $token = strtok($string, '.');

        $ref =& $return;     

        while($token !== false)
        {  

            $ref =& $ref[$token];
            $token = strtok('.');
        }

        $ref = $value;
        $array = $return;
    }

    reference_dot_notation('person.name', 'Wallace', $test2);
    reference_dot_notation('person.lastname', 'Maxters', $test2);

    var_export($test2);

    /**
        array (
          'person' => 
          array (
            'name' => 'Wallace',
            'lastname' => 'Maxters',
          ),
        )

    */

#5


3  

I created a small class just for this!

我为此创建了一个小班级!

http://github.com/projectmeta/Stingray

http://github.com/projectmeta/Stingray

$stingray = new StingRay();

//To Get value
$stingray->get($array, 'this.that.someother'):

//To Set value
$stingray->get($array, 'this.that.someother', $newValue):

#6


0  

Updated @hair resins' answer to cater for:

更新了@hair树脂的答案,以满足:

  • When a sub-path already exists, or
  • 当子路径已经存在时,或
  • When a sub-path is not an array

    当子路径不是数组时

    function set_val(array &$arr, $path,$val)
    {
       $loc = &$arr;
       $path = explode('.', $path);
       foreach($path as $step)
       {
           if ( ! isset($loc[$step]) OR ! is_array($loc[$step]))
               $loc = &$loc[$step];
       }
       return $loc = $val;
    }