Everybody knows that you can access a variable in PHP using this: ${'varName'}. But when you need to get/set a variable witch is part of an array, why doesn't it work ? Suppose we have this piece of code:
<?php
$myArray = array(...);
$myVarName = "myArray['my1']['my11']['my111']";
${$myVarName} = "new value";
?>
Shouldn't it work ?
I have tested it again and again - it is not working..
Is it there a way to do that?
I recommend you not to use dynamic variables like ${$var}.
What you want is modifying a multi-dimensional associative array according to a path of keys.
<?php
$myArray = array(...); // multi-dimensional array
$myVarPath = array('my1', 'my11', 'my111');
setValueFromPath($myArray, $myVarPath);
function getValueFromPath($arr, $path)
{
// todo: add checks on $path
$dest = $arr;
$finalKey = array_pop($path);
foreach ($path as $key) {
$dest = $dest[$key];
}
return $dest[$finalKey];
}
function setValueFromPath(&$arr, $path, $value)
{
// we need references as we will modify the first parameter
$dest = &$arr;
$finalKey = array_pop($path);
foreach ($path as $key) {
$dest = &$dest[$key];
}
$dest[$finalKey] = $value;
}
This is a procedural example to keep it simple. You may want to put your hierarchical array and this functions inside a class.
Shouldn't it work ?
No.
Everybody knows that you can access a variable in PHP using this: ${'varName'}.
Yes. Yet everybody knows that's lame.
How to refer dynamically to a php array variable(s)?
having array of ('my1','my11','my111') you can refer to any particular array member using merely a loop.
You could do something like this, but it would be a really bad idea. Sorry Col. ;)
<?php
$mA = array();
$mVN = "mA['m1']['m2']['m3']";
eval('$'. $mVN . ' = "new value";');
print_r($mA);
?>
Related
I have an small piece of PHP code that needs to put every file in the current directory into an array.
I have done this by making reading the dir with glob() and when it meets another dir it will loop.
My code I have as of now:
<?php
$find = '*';
$result = array();
function find($find)
{
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
find($zoek);
}
}
return $result;
}
print_r(find($find));
?>
When I execute the code the echo print exactly what I want. But the printed array doesn't give me the values I want, it only gives the values in the first dir it will come by then it seems to stop adding the value in the array.
What am I doing wrong?
You need to actually preserve the results you produce in the recursive callings to your function:
<?php
function listNodesInFolder($find) {
$result = [];
foreach (glob($find) as $entry) {
$result[] = $entry;
if (is_dir($entry)) {
$result = array_merge($result, find($entry.'/*'));
}
}
return $result;
}
print_r(find('*'));
Once on it I also fixes a few other issues with your code:
$result should be declared as an array inside your function, that that even if it does not loop you still return an array and not something undefined.
indentation and location of brackets got adjusted to general coding standards, that makes reading your code much easier for others. Get used to those standards, it pays out, you will see.
no need for an extra variable for the search pattern inside the conditional.
a speaking name for the function that tells what it actually does.
you should not name variables and functions alike ("find").
You need to add the result of find() to the array
Edit added array_merge - Cid's idea
<?php
$find = '*';
function find($find)
{
$result = array();
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
$result = array_merge($result, find($zoek));
}
}
return $result;
}
print_r(find($find));
?>
Is it possible to create a variable variable pointing to an array or to nested objects? The php docs specifically say you cannot point to SuperGlobals but its unclear (to me at least) if this applies to arrays in general.
Here is my try at the array var var.
// Array Example
$arrayTest = array('value0', 'value1');
${arrayVarTest} = 'arrayTest[1]';
// This returns the correct 'value1'
echo $arrayTest[1];
// This returns null
echo ${$arrayVarTest};
Here is some simple code to show what I mean by object var var.
${OBJVarVar} = 'classObj->obj';
// This should return the values of $classObj->obj but it will return null
var_dump(${$OBJVarVar});
Am I missing something obvious here?
Array element approach:
Extract array name from the string and store it in $arrayName.
Extract array index from the string and store it in $arrayIndex.
Parse them correctly instead of as a whole.
The code:
$arrayTest = array('value0', 'value1');
$variableArrayElement = 'arrayTest[1]';
$arrayName = substr($variableArrayElement,0,strpos($variableArrayElement,'['));
$arrayIndex = preg_replace('/[^\d\s]/', '',$variableArrayElement);
// This returns the correct 'value1'
echo ${$arrayName}[$arrayIndex];
Object properties approach:
Explode the string containing the class and property you want to access by its delimiter (->).
Assign those two variables to $class and $property.
Parse them separately instead of as a whole on var_dump()
The code:
$variableObjectProperty = "classObj->obj";
list($class,$property) = explode("->",$variableObjectProperty);
// This now return the values of $classObj->obj
var_dump(${$class}->{$property});
It works!
Use = & to assign by reference:
$arrayTest = array('value0', 'value1');
$arrayVarTest = &$arrayTest[1];
$arrayTest[1] = 'newvalue1'; // to test if it's really passed by reference
print $arrayVarTest;
In echo $arrayTest[1]; the vars name is $arrayTest with an array index of 1, and not $arrayTest[1]. The brackets are PHP "keywords". Same with the method notation and the -> operator. So you'll need to split up.
// bla[1]
$arr = 'bla';
$idx = 1;
echo $arr[$idx];
// foo->bar
$obj = 'foo';
$method = 'bar';
echo $obj->$method;
What you want to do sounds more like evaluating PHP code (eval()). But remember: eval is evil. ;-)
Nope you can't do that. You can only do that with variable, object and function names.
Example:
$objvar = 'classObj';
var_dump(${$OBJVarVar}->var);
Alternatives can be via eval() or by doing pre-processing.
$arrayTest = array('value0', 'value1');
$arrayVarTest = 'arrayTest[1]';
echo eval('return $'.$arrayVarTest.';');
eval('echo $'.$arrayVarTest.';');
That is if you're very sure of what's going to be the input.
By pre-processing:
function varvar($str){
if(strpos($str,'->') !== false){
$parts = explode('->',$str);
global ${$parts[0]};
return $parts[0]->$parts[1];
}elseif(strpos($str,'[') !== false && strpos($str,']') !== false){
$parts = explode('[',$str);
global ${$parts[0]};
$parts[1] = substr($parts[1],0,strlen($parts[1])-1);
return ${$parts[0]}[$parts[1]];
}else{
return false;
}
}
$arrayTest = array('value0', 'value1');
$test = 'arrayTest[1]';
echo varvar($test);
there is a dynamic approach for to many nested levels:
$attrs = ['level1', 'levelt', 'level3',...];
$finalAttr = $myObject;
foreach ($attrs as $attr) {
$finalAttr = $finalAttr->$attr;
}
return $finalAttr;
For example, I have the following:
$ValuePath = "object->data->user_nicename";
And I need to print not the value of the $ValuePath but the value of the $variable->data->user_nicename that is part of a larger call .. as I have the following situation:
echo $objects->$ValuePath->details;
and is not working .. I'm getting the error Class cannot be converted to string or something when I try it like that.
PHP pseudo-code:
function get_by_path($object, $path)
{
$o = $object;
$parts = explode('->', $path);
// if you want to remove the first dummy object-> reference
array_shift($parts);
$l = count($parts);
while ($l)
{
$p = array_shift($parts); $l--;
if ( isset($o->{$p}) ) $o = $o->{$p};
else {$o = null; break;}
}
return $o;
}
Use like this:
$value = get_by_path($obj, "object->data->user_nicename");
// $value = $obj->data->user_nicename;
Check also PHP ArrayAccess Interface which enables to access objects as arrays dynamicaly
NO you cannot do that.
From your declaration $ValuePath is a variable which holds a plain string ('object->data->user_nicename') this string is not an object.
Where as,
$objects->object->data->user_nicename->details is a object.
so $objects->object->data->user_nicename->details is not same as $objects->$ValuePath->details
Do you know a better way to do thing when it comes to assigning values to a large number of variables after an if?
In my case it like this:
$akeType = array_key_exists('type',$handle);
$akeParent = array_key_exists('parent',$handle);
$akeUserName = array_key_exists('userName',$handle);
$akeUserId = array_key_exists('userId',$handle);
$akeCountryCode = array_key_exists('userId',$handle);
if ( $akeType && $akeParent && $akeUserName && $akeUserId & $akeCountryCode ) {
$listType = $handle['type'];
$listParent = $handle['parent'];
$listUserName = $handle['userName'];
$listUserId = $handle['userId'];
$foo = $_POST['foo'];
$bar = $_POST['bar'];
$listCountryCode = $handle['countryCode']; // Is there a way to clean up this part? The assignments to variables.
take a look at the extract -- Import variables into the current symbol table from an array
extract($handle, EXTR_OVERWRITE, "ake_");
You can do this with the somewhat more obscure code following:
$keys= array('type','parent','userName', 'userId');
foreach($keys as $key) {
$nametoset= "list".ucfirst($key);
$$nametoset= $handle[$key];
}
$$nametoset refers to the variable named like the string $nametoset.
Similar code may be used for the $ake... variables.
You can use Variable variables to set your variable list.
For your specific case, you can use the following code:
foreach ($handle as $key => $value) {
$var_name = 'list'.$key;
$$var_name = $value;
}
foreach ($_POST as $pkey => $pvalue) {
$$pkey = $pvalue;
}
These loops create variables depending on your arrays keys.
I have a recursive array depth of which is variable, and I want to be able to take a string with a separator and convert that string to an index in that array,
For example
$path = 'level1.level2.level3';
will be converted to get the value 'my data' from the array below
$data['level1']['level2']['level3'] = 'my data';
I thought the quickest way to get this would be to use variable variables, but when I try the following code
$index = "data['level1']['level2']['level3']";
echo $$index;
I get the follwing error
PHP Notice: Undefined variable: data['level1']['level2']['level3']
All other ways I can think of doing this are very inefficient, could someone please shed some light on this, is it possible using variable variables for arrays in PHP? Any other efficient workaround?
Many thanks.
You'll have to loop the array, you won't manage to do this using variable variables, as far as I know. This seems to work though:
<?php
function retrieve( $array, $path ) {
$current = $array;
foreach( explode( '.', $path ) as $segment ) {
if( false === array_key_exists( $segment, $current ) ) {
return false;
}
$current = $current[$segment];
}
return $current;
}
$path = 'level1.level2.level3';
// will be converted to get the value 'my data' from the array below
$data['level1']['level2']['level3'] = 'my data';
var_dump( retrieve( $data, $path ) );
It is a tricky one this, here is the most efficient way I can think of:
function get_value_from_array ($array, $path, $pathSep = '.') {
foreach (explode($pathSep, $path) as $pathPart) {
if (isset($array[$pathPart])) {
$array = $array[$pathPart];
} else {
return FALSE;
}
}
return $array;
}
Returns the value, or FALSE on failure.
Try
$index = "data";
echo $$index['level1']['level2']['level3'];
instead, because $index should be only variable name
Something like this:
eval('$data[\''.implode("']['",explode('.',$path))."'] = 'my data';");
...but don't ever, ever tell anyone I told you to do this.
You can use eval function like so:
$data['level1']['level2']['level3'] = 'my data';
eval("\$index = \$data['level1']['level2']['level3'];");
echo $index;