2011-12-02 44 views
5

tôi muốn tự động giá trị truy cập của biến, chúng ta hãy nói rằng tôi có mảng này:PHP tự động truy cập vào biến giá trị

$aData = array(
    'test' => 123 
); 

phương pháp tiêu chuẩn để in các giá trị quan trọngtestsẽ là:

print $aData['test']; 

Tuy nhiên, nếu tôi phải làm việc với biểu diễn chuỗi biến (cho mục đích động)

$sItem = '$aData[\'test\']'; 

cách tôi có thể đạt được để in aDatakhóa có tên test? Không có ví dụ nào được cung cấp bên dưới hoạt động

print $$sItem; 
print eval($sItem); 

Giải pháp là gì?

Trả lời

6

dụ eval của bạn là thiếu giá trị trả về:

print eval("return $sItem;"); 

nên làm điều đó:

$aData['test'] = 'foo'; 

$sItem = '$aData[\'test\']'; 

print eval("return $sItem;"); # foo 

Nhưng không nên sử dụng eval bình thường. Bạn có thể vào bếp của địa ngục với nó bởi vì eval là ác.

Thay vì chỉ phân tích chuỗi và trả về giá trị:

$aData['test'] = 'foo'; 

$sItem = '$aData[\'test\']'; 

$r = sscanf($sItem, '$%[a-zA-Z][\'%[a-zA-Z]\']', $vName, $vKey); 
if ($r === 2) 
{ 
    $result = ${$vName}[$vKey]; 
} 
else 
{ 
    $result = NULL; 
} 

print $result; # foo 

Điều này có thể được thực hiện với một số hình thức khác của biểu thức chính quy là tốt.

Khi cú pháp của bạn rất gần với PHP thực sự là một tập hợp con của nó, có một số thay thế bạn có thể làm nếu bạn muốn xác thực đầu vào trước khi sử dụng eval. Phương pháp này là để kiểm tra mã PHP và chỉ cho phép một tập hợp con. Điều này không xác thực chuỗi (ví dụ: cú pháp và nếu biến thực sự được đặt) nhưng làm cho nó trở nên nghiêm ngặt hơn:

function validate_tokens($str, array $valid) 
{ 
    $vchk = array_flip($valid); 
    $tokens = token_get_all(sprintf('<?php %s', $str)); 
    array_shift($tokens); 
    foreach($tokens as $token) 
     if (!isset($vchk[$token])) return false; 
    return true; 
} 

Bạn chỉ cần cung cấp một mảng mã thông báo hợp lệ cho chức năng đó. Đó là những thẻ PHP, trong trường hợp của bạn đó là:

T_LNUMBER (305) (probably) 
T_VARIABLE (309) 
T_CONSTANT_ENCAPSED_STRING (315) 

Sau đó, bạn chỉ có thể sử dụng nó và nó hoạt động với các phím phức tạp hơn cũng như:

$aData['test'] = 'foo'; 
$aData['te\\\'[]st']['more'] = 'bar'; 

$sItem = '$aData[\'test\']'; 
$vValue = NULL; 
if (validate_tokens($sItem, array(309, 315, '[', ']'))) 
{ 
    $vValue = eval("return $sItem;"); 
} 

tôi đã sử dụng này trong another answer của câu hỏi reliably convert string containing PHP array info to array.

+0

@all: cảm ơn tất cả các bạn, từ những gì tôi định làm (trong bức tranh lớn) giải pháp tốt nhất cho tôi để sử dụng chức năng eval ... tôi chỉ quên sử dụng return – nabizan

1

Giải pháp duy nhất trong trường hợp của bạn là sử dụng Eval().

Nhưng hãy rất cẩn thận khi thực hiện việc này! Đánh giá sẽ đánh giá (và thực hiện) bất kỳ đối số nào bạn chuyển cho nó dưới dạng PHP. Vì vậy, nếu bạn sẽ cho nó một cái gì đó đến từ người dùng, sau đó bất cứ ai có thể thực thi bất kỳ mã PHP trên máy chủ của bạn, mà đi mà không nói là một lỗ hổng bảo mật kích thước của Grand Canyon !.

chỉnh sửa: bạn sẽ phải đặt "in" hoặc "echo" bên trong biến số $sItem của bạn bằng cách nào đó. Nó sẽ phải ở trong $sItem ($sItem = 'echo $aData[\'test\']';) hoặc bạn sẽ phải viết Eval() như sau: Eval ('echo ' . $sData).

+0

Không chỉ eval thể – azat

+0

Theo câu hỏi của anh ấy. –

+0

xem nhận xét của tôi http://stackoverflow.com/a/8356802/328260 – azat

3

Bạn chỉ có thể sử dụng nó như một mảng bình thường:

$key = "test"; 

print $aData[$key]; 

Tương tự như vậy $aData bản thân có thể là một mục trong một cửa hàng mảng lớn hơn.


Thay thế, trích xuất các khóa mảng tiềm năng bằng cách sử dụng regex và duyệt qua một mảng ẩn danh (nên đề cập trong câu hỏi của bạn, nếu) có tham chiếu. Xem Set multi-dimensional array by key path from array values? và các chủ đề tương tự.


Cá nhân tôi đang sử dụng cấu trúc như thế này để sử dụng đường dẫn biến động như varname[keyname] thay vào đó (tương tự như cách PHP diễn giải tham số GET). Nó chỉ là một eval trong cừu quần áo (không đồng ý với các scaremongering eval dù):

$val = preg_replace("/^(\w)+(\[(\w+)])$/e", '$\1["\3"]', "aData[test]"); 
+0

Ngoài thực tế là bạn có thể có nghĩa là in $ aData [$ key] và không phải $ aData [$ test], đây là giải pháp tốt nhất cho đến nay . +1 –

+1

Nếu bạn bỏ qua những gì được hỏi thì đó là giải pháp tốt nhất, vâng! :) –

+0

+1. Tôi nghĩ đây là giải pháp hợp lý và duy nhất. Không có vấn đề làm thế nào những người khác đã đề nghị sử dụng 'eval', không ai trong số họ sẽ làm việc để trả về _key_' test'. Có lẽ một số phân tích chuỗi regex sẽ đạt được để trích xuất khóa, nhưng eval sẽ không bao giờ quản lý để làm điều đó dựa trên cách OP có chuỗi. – Shef

1
$sItem = '$aData[\'test\']'; 
eval('$someVar = '.$sItem.';'); 
echo $someVar; 

Sử dụng eval() với sự thận trọng cao như những người khác đã giải thích.

4

Không eval cần thiết nếu bạn có (hoặc có thể nhận được) tên mảng và chìa khóa vào biến riêng biệt:

$aData = array(
    'test' => 123 
); 

$arrayname = 'aData'; 
$keyname = 'test'; 

print ${$arrayname}[$keyname]; // 123 
1

Bạn có thể sử dụng phương pháp này

function getRecursive($path, array $data) { 
     // transform "foo['bar']" and 'foo["bar"]' to "foo[bar]" 
     $path = preg_replace('@\[(?:"|\')(.+)(?:"|\')\]@Uis', '[\1]', $path); 

     // get root 
     $i = strpos($path, '['); 
     $rootKey = substr($path, 0, $i); 
     if (!isset($data[$rootKey])) { 
      return null; 
     } 
     $value = $data[$rootKey]; 

     $length = strlen($path); 
     $currentKey = null; 
     for (; $i < $length; ++$i) { 
      $char = $path[$i]; 

      switch ($char) { 
       case '[': 
        if ($currentKey !== null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "[" at position %u', $i)); 
        } 
        $currentKey = ''; 
        break; 
       case ']': 
        if ($currentKey === null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "]" at position %u', $i)); 
        } 

        if (!isset($value[$currentKey])) { 
         return null; 
        } 

        $value = $value[$currentKey]; 
        if (!is_array($value)) { 
         return $value; 
        } 

        $currentKey = null; 
        break; 
       default: 
        if ($currentKey === null) { 
         throw new InvalidArgumentException(sprintf('Malformed path, unexpected "%s" at position %u', $char, $i)); 
        } 
        $currentKey .= $char; 
        break; 
      } 
     } 

     if ($currentKey !== null) { 
      throw new InvalidArgumentException('Malformed path, must be and with "]"'); 
     } 

     return $value; 
    } 
+0

Đó là một cách tiếp cận tốt. Tuy nhiên, một 'preg_match_all' duy nhất sẽ đủ để nhận các khóa mảng cùng lúc, tích lũy' ['phân tích cú pháp'] '. – mario

+0

@mario cảm ơn.Hãy cho tôi như vậy xin vui lòng, với cho rằng khóa như vậy không thể tồn tại trong mảng – azat

+0

@mario, Bạn pcre không hoạt động – azat

Các vấn đề liên quan