1

I have an array of user inputs ($atts) as key=>value pairs. Some of the values could be written as an array expression, such as:

'setting' => 'array(50,25)'

In those cases, I would like to convert the array expression contained in that string into an actual array. So the output would be something like:

$atts = array(
'setting' => array(50,25),
'another' => 'not written as an array expression'
)

Written logically, the code would be:

For each key=>value pair in the array $atts... if the value is a string formatted as an array expression... explode that value into an array.

Anybody know how I would write this in PHP?

2
  • 1
    I will not write this into an answer to prevent infinite downvotes, but ... eval: php.net/manual/en/function.eval.php BTW, wouldn't it be better to use JSON + json_encode/decode? Commented Jun 29, 2012 at 18:56
  • @biziclop That looks like it only works on PHP 5 >= 5.2.0, but my solution needs to work with PHP 4.3 or higher. It is for a WordPress plugin. Commented Jun 29, 2012 at 19:03

4 Answers 4

3
function stringToArray($string) {
        $string = "return " . $string . ";";
        if (function_exists("token_get_all")) {//tokenizer extension may be disabled
            $php = "<?php\n" . $string . "\n?>";
            $tokens = token_get_all($php);
                        foreach ($tokens as $token) {
                $type = $token[0];
                if (is_long($type)) {
                    if (in_array($type, array(
                            T_OPEN_TAG, 
                            T_RETURN, 
                            T_WHITESPACE, 
                            T_ARRAY, 
                            T_LNUMBER, 
                            T_DNUMBER,
                            T_CONSTANT_ENCAPSED_STRING, 
                            T_DOUBLE_ARROW, 
                            T_CLOSE_TAG,
                            T_NEW,
                            T_DOUBLE_COLON
                            ))) {
                        continue;
                    }


                    exit("For your security, we stoped data parsing at '(" . token_name($type) . ") " . $token[1] . "'.");
                }
            }
        }

        return eval($string);
    }

$a='array(10,20)';
print_r(stringToArray($a));
Sign up to request clarification or add additional context in comments.

Comments

2

Use the tokenizer:

function stringToArray($str) {
    $array = array();
    $toks = token_get_all("<?php $str");

    if ($toks[1][0] != T_ARRAY || $toks[2] != '(' || end($toks) != ')')
        return null;

    for($i=3; $i<count($toks)-1; $i+=2) {
        if (count($toks[$i]) != 3)
            return null;

        if ($toks[$i][0] == T_WHITESPACE) {
            $i--;
            continue;
        }

        if ($toks[$i][0] == T_VARIABLE || $toks[$i][0] == T_STRING)
            return null;

        $value = $toks[$i][1];
        if ($toks[$i][0] == T_CONSTANT_ENCAPSED_STRING)
            $value = substr($value, 1, strlen($value) - 2);

        $array[] = $value;

        if ($toks[$i + 1] != ',' && $toks[$i + 1] != ')' && $toks[$i + 1][0] != T_WHITESPACE)
            return null;
    }

    return $array;
}

The above will work only for literals. Passing a variable, a constant, an expression, a nested array or a malformed array declaration will return null:

stringToArray('array(1,2)');              // works
stringToArray('array(1,2.4)');            // works
stringToArray('array("foo",2)');          // works
stringToArray('array(\'hello\',2)');      // works
stringToArray('array()');                 // works
stringToArray('array(1,2 + 3)');          // returns null
stringToArray('array(1,2 + 3)');          // returns null
stringToArray('array("foo"."bar")');      // returns null
stringToArray('array(array("hello"))');   // returns null
stringToArray('array($a,$b)');            // returns null
stringToArray('array(new bar)');          // returns null
stringToArray('array(SOME_CONST)');       // returns null
stringToArray('hello');                   // returns null

You can also use the following to check if your string is an array expression or not:

function isArrayExpression($str) {
    $toks = token_get_all("<?php $str");
    return (
        $toks[1][0] == T_ARRAY &&
        $toks[2] == '(' &&
        end($toks) == ')'
    );
}

isArrayExpression('array(1,2,3)');         // true
isArrayExpression('array is cool');        // false
isArrayExpression('array(!!!!');           // false

You can always tweak it to your needs. Hope this helps.

3 Comments

Thanks @netcoder! I will experiment with this, although I will need to get it to work with nested arrays as well...
@Shaun Scovil: Shouldn't be that hard. Check if the token is a T_ARRAY and if it is, call a recursive function.
This worked out great, thank you! I'm still trying to wrap my mind around recursive functions, but once I figure that out I will post my full solution for others...
0

As suggested in the comments of your post, eval() will do what you're looking for. However it's not really practical to store arrays as strings in the first place. If you're looking to make data more portable, I'd recommend using json_encode() or even serialize()

4 Comments

As I mentioned to Kris, I'm essentially just writing a function that accepts parameters, then passes those parameters to another function. But some of those parameters must be arrays, so the first function receives them as strings and must then convert them to arrays before passing to the second function.
You do know that you can pass arrays as function arguments directly, right? From your description, it doesn't sound like you should have to make an array string.
The parameters for my function ($atts) are set by the user through the WordPress Shortcode API, so the format they use is something like [wpquery setting="array(50, 25)" another="blah"] -- which I must then translate into a multidimensional array and pass to the WP_Query function as array('setting'=>array(50,25),'another'=>'blah').
I see. Well that's annoying. You may have to expand on netcoder's answer.
0

You can use eval, but I would highly recommend not using it, and instead try to rethink your design on a better way to handle the settings. So for your example instead of storing

'setting' => 'array(50,25)'

Could you do something like

'setting' => array('type'=>'array', 'value'=>'50, 25')

then when you load the settings you can do

switch($type)
case 'array'
  $val = explode(', ', $value)

Or something similar

But like others suggested, I would try to save the settings using serialization

3 Comments

I suppose this requires a little more explanation. I've written a WordPress plugin that allows WP website admins to run the built-in WP function WP_Query (codex.wordpress.org/Class_Reference/WP_Query) from a post or page using shortcode. So the shortcode parameters are the same parameters that will be passed to WP_Query. However, some of those parameters must be written as arrays. I don't want to over-complicate the shortcode, so I'd like to just let the user write [wpquery setting="array(50,25)" another="blah"]. Does that make sense?
ah ok. Sorry I know nothing about WP so can't give suggestions on a better way.
Well, all you really need to know is that I'm writing a function that accepts parameters, then passes them to another function. They just need to be arrays occasionally, rather than strings. It's still just PHP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.