2012-03-09 21 views
28

Tôi có trường hợp sử dụng bất thường mà tôi đang cố gắng mã hóa. Mục tiêu là thế này: Tôi muốn các khách hàng để có thể cung cấp một chuỗi, chẳng hạn như:Sử dụng đường dẫn chuỗi để đặt dữ liệu mảng lồng nhau

"cars.honda.civic = On" 

Sử dụng chuỗi này, mã của tôi sẽ đặt một giá trị như sau:

$data['cars']['honda']['civic'] = 'On'; 

Thật dễ dàng đủ tokenize đầu vào của khách hàng như vậy:

$token = explode("=",$input); 
$value = trim($token[1]); 
$path = trim($token[0]); 
$exploded_path = explode(".",$path); 

Nhưng bây giờ, làm thế nào để tôi sử dụng đường $ nổ để thiết lập mảng mà không làm một cái gì đó khó chịu như một eval?

Trả lời

56

Sử dụng các nhà điều hành tài liệu tham khảo để có được những mảng hiện liên tiếp:

$temp = &$data; 
foreach($exploded as $key) { 
    $temp = &$temp[$key]; 
} 
$temp = $value; 
unset($temp); 
+1

Điều đó thật tuyệt vời. :) Cảm ơn alexisdm! – Anthony

+0

Có cách nào để lấy giá trị thay vì cài đặt không? –

+0

@MaraisRossouw nhận xét/câu hỏi của bạn cũ, nhưng hãy xem http://stackoverflow.com/a/36042293/1371433 nó hoạt động như getter và/hoặc setter –

3
$data = $value; 
foreach (array_reverse($exploded_path) as $key) { 
    $data = array($key => $data); 
} 
+1

Trừ khi bạn sử dụng một cái gì đó như 'array_merge_recursive', bạn đang thay thế các giá trị trước đó đã là $ dữ liệu đã chứa. – alexisdm

+1

Đó thực sự là một điểm tốt, giả sử rằng '$ data' đã chứa giá trị. – deceze

-4

thể bạn không chỉ cần làm điều này

$exp = explode(".",$path); 
$array[$exp[0]][$exp[1]][$exp[2]] = $value 
+3

Tôi chỉ đơn giản giả định rằng số lượng '$ exp' * không cố định *! – deceze

+0

lừa dối là chính xác - Tôi không thể giả định tôi sẽ biết có bao nhiêu nút mà khách hàng sẽ cung cấp. Cảm ơn phản hồi, mặc dù. – Anthony

13

Dựa trên alexisdm's response:

/** 
* Sets a value in a nested array based on path 
* See https://stackoverflow.com/a/9628276/419887 
* 
* @param array $array The array to modify 
* @param string $path The path in the array 
* @param mixed $value The value to set 
* @param string $delimiter The separator for the path 
* @return The previous value 
*/ 
function set_nested_array_value(&$array, $path, &$value, $delimiter = '/') { 
    $pathParts = explode($delimiter, $path); 

    $current = &$array; 
    foreach($pathParts as $key) { 
     $current = &$current[$key]; 
    } 

    $backup = $current; 
    $current = $value; 

    return $backup; 
} 
+0

điều chỉnh nhỏ: chức năng này sẽ gây tử vong nếu một trong các "nút" dọc theo đường dẫn đã được đặt nhưng không phải là một mảng. '$ a = ['foo' => 'không phải là mảng']; set_nested_array ($ a, 'foo/bar', 'new value'); 'fix: chèn đầu tiên làm dòng đầu tiên cho foreach' if (! is_array ($ current)) {$ current = array(); } ' –

3

Dựa trên Ugo Méda's response:

Phiên bản này

  • cho phép bạn sử dụng nó chỉ như một getter (rời khỏi mảng nguồn bị ảnh hưởng)
  • sửa chữa các vấn đề lỗi nghiêm trọng nếu một giá trị không phải là mảng được gặp (Cannot create references to/from string offsets nor overloaded objects)

không lỗi nghiêm trọng ví dụ

$a = ['foo'=>'not an array']; 
arrayPath($a, ['foo','bar'], 'new value'); 

$a tại là

array(
    'foo' => array(
     'bar' => 'new value', 
    ), 
) 

Sử dụng như một getter

$val = arrayPath($a, ['foo','bar']); // returns 'new value'/$a remains the same 

Set giá trị null

$v = null; // assign null to variable in order to pass by reference 
$prevVal = arrayPath($a, ['foo','bar'], $v); 

$prevVal là "giá trị mới"
$a tại là

array(
    'foo' => array(
     'bar' => null, 
    ), 
) 

 

/** 
* set/return a nested array value 
* 
* @param array $array the array to modify 
* @param array $path the path to the value 
* @param mixed $value (optional) value to set 
* 
* @return mixed previous value 
*/ 
function arrayPath(&$array, $path = array(), &$value = null) 
{ 
    $args = func_get_args(); 
    $ref = &$array; 
    foreach ($path as $key) { 
     if (!is_array($ref)) { 
      $ref = array(); 
     } 
     $ref = &$ref[$key]; 
    } 
    $prev = $ref; 
    if (array_key_exists(2, $args)) { 
     // value param was passed -> we're setting 
     $ref = $value; // set the value 
    } 
    return $prev; 
} 
+0

Bạn có thể tùy ý kiểm tra xem đường dẫn có phải là một chuỗi không và chuyển đổi thành một mảng có phát nổ, ví dụ: '$ path = explode ('.', $ path);' để bạn có thể sử dụng ký pháp chấm phổ biến, ví dụ: '$ val = arrayPath ($ a, 'foo.bar');' – AVProgrammer

2

Vâng thử nghiệm và 100% làm việc mã. Đặt, nhận, bỏ đặt giá trị từ mảng bằng cách sử dụng "cha mẹ". Cha mẹ có thể là array('path', 'to', 'value') hoặc một chuỗi path.to.value.Dựa trên mã của Drupal

/** 
* @param array $array 
* @param array|string $parents 
* @param string $glue 
* @return mixed 
*/ 
function array_get_value(array &$array, $parents, $glue = '.') 
{ 
    if (!is_array($parents)) { 
     $parents = explode($glue, $parents); 
    } 

    $ref = &$array; 

    foreach ((array) $parents as $parent) { 
     if (is_array($ref) && array_key_exists($parent, $ref)) { 
      $ref = &$ref[$parent]; 
     } else { 
      return null; 
     } 
    } 
    return $ref; 
} 

/** 
* @param array $array 
* @param array|string $parents 
* @param mixed $value 
* @param string $glue 
*/ 
function array_set_value(array &$array, $parents, $value, $glue = '.') 
{ 
    if (!is_array($parents)) { 
     $parents = explode($glue, (string) $parents); 
    } 

    $ref = &$array; 

    foreach ($parents as $parent) { 
     if (isset($ref) && !is_array($ref)) { 
      $ref = array(); 
     } 

     $ref = &$ref[$parent]; 
    } 

    $ref = $value; 
} 

/** 
* @param array $array 
* @param array|string $parents 
* @param string $glue 
*/ 
function array_unset_value(&$array, $parents, $glue = '.') 
{ 
    if (!is_array($parents)) { 
     $parents = explode($glue, $parents); 
    } 

    $key = array_shift($parents); 

    if (empty($parents)) { 
     unset($array[$key]); 
    } else { 
     array_unset_value($array[$key], $parents); 
    } 
} 
0

Bạn cần sử dụng Symfony PropertyPath

<?php 
// ... 
$person = array(); 

$accessor->setValue($person, '[first_name]', 'Wouter'); 

var_dump($accessor->getValue($person, '[first_name]')); // 'Wouter' 
// or 
// var_dump($person['first_name']); // 'Wouter' 
Các vấn đề liên quan