How to send an indexes name for php array vairable.
the array is
$array = array('Somthing'=>array('More'=>array('id'=> 34)));
and now I want to display this thing but with a variable name I don't know how to explain so I write what I want to have.
$index_name = '[Something][More][id]';
$array{$index_name};
Is it possible in any way ?
Not in one go like that. Here's how you'd do it:
$array['Something']['More']['id']
If you particularly wanted access multidimensional arrays with a single string, then you could build a function to do that:
function array_multi(Array $arr, $path) {
$parts = explode(".", $path);
$curr =& $arr;
for ($i = 0, $l = count($parts); $i < $l; ++$i) {
if (!isset($curr[$parts[$i]])) {
// path doesn't exist
return null;
} else if (($i < $l - 1) && !is_array($curr[$parts[$i]]) {
// path doesn't exist
return null;
}
$curr =& $curr[$parts[$i]];
}
return $curr;
}
// usage:
echo array_multi($array, "Something.More.id"); // 34
echo array_multi($array, "Something.More"); // array("id" => 34)
Recursive version supporting your syntax with square brackets:
$array = array('Something'=>array('More'=>array('id'=> 34)));
$string = '[Something][More][id]';
echo scan_array($string, $array);
function scan_array($string, $array) {
list($key, $rest) = preg_split('/[[\]]/', $string, 2, PREG_SPLIT_NO_EMPTY);
if ( $key && $rest ) {
return scan_array($rest, $array[$key]);
} elseif ( $key ) {
return $array[$key];
} else {
return FALSE;
}
}
Ok, I know this is how people get shot. But c'mon, eval() is not always the wrong answer.
$array = array('Something'=>array('More'=>array('id'=> 34)));
$index_name = '[Something][More][id]';
eval('$val = $array'.$index_name.';'); // Wrap in a function or something
You could do this with eval():
<?php
$array = array('Somthing'=>array('More'=>array('id'=> 34)));
$index_name = "['Somthing']['More']['id']";
$stmt='echo $array'.$index_name.';';
eval($stmt);
?>
UPDATE:
It seems some SO users are uncomfortable with the idea of using eval(). I think it makes sense to read this thread which discusses the pros and cons before deciding whether to use this in your own code.
If you've cornered yourself into needing to do something like this, there's a pretty good chance you've done something else in a poor way. There's valid reasons to do this, but not very often.
function key_path($arr, $keys) {
return $keys ? key_path($arr[array_shift($keys)], $keys) : $arr;
}
$arr['Something']['More']['id'] = 34;
$keys = array('Something', 'More', 'id');
var_dump( key_path($arr, $keys));
Related
I can easily write to and read from a sub-array in the session array.
$_SESSION['a']['b']['c']['value']=123;
$val=$_SESSION['a']['b']['c']['value'];
Instead of hard coding the "location" where the value is written, I would like it to be definable via a string or some other way. The following will obviously not work, but hopefully will better explain the intent.
$prefix="['a']['b']['c']"; //defined in config page, etc
$_SESSION.$prefix.['value']=123;
$val=$_SESSION.$prefix.['value'];
How can this be accomplished?
PropertyAccess
There is an excellent Symfony component for such tasks, named PropertyAccess. You can use it as follows:
$persons = array('a' => array('b' => 5.7));
$accessor = PropertyAccess::createPropertyAccessor();
echo $accessor->getValue($persons, '[a][b]'); // 5.7
You can install it using Composer as described in docs or fetch directly from GitHub.
Custom solution
This is a complete solution, I'm really impressed that it works... but it works! Check the code below, assert()'s demonstrate the usage:
<?php
function arrayPropertyPathGet(array $arr, $path) {
$parts = explode('.', $path);
$ret = $arr;
foreach($parts as $part) {
$ret = $ret[$part];
}
return $ret;
}
function arrayPropertyPathSet(array &$arr, $path, $value) {
$parts = explode('.', $path);
$tmp = &$arr;
foreach($parts as $part) {
if(!isset($tmp[$part])) { return false; }
$tmp = &$tmp[$part];
}
$tmp = $value;
return true;
}
$test = array('a' => array('b' => 'value'));
assert('value' === arrayPropertyPathGet($test, 'a.b'));
assert(true === arrayPropertyPathSet($test, 'a.b', 'other'));
assert('other' === arrayPropertyPathGet($test, 'a.b'));
Side note
As a theoretical side note (do not use this for anything other than learning purposes) you can experiment with eval(), such as:
eval("$value = $persons['a']['b']");
I faced the same problem a few times ago, and as I didn't find any solution, I made one by myself, if that can help you in anyway (only the interesting part) :
class ArrayAccessor {
private $prefix;
function setPrefix() {
$this->prefix = array();
for ($i = 0; $i < func_num_args(); ++$i) {
$this->prefix[] = func_get_arg($i);
}
}
function getFromPrefix(array $array) {
$tmp_array = $array;
foreach ($this->prefix as $pre) {
if (isset ($tmp_array[$pre])) {
$tmp_array = $tmp_array[$pre];
} else {
return null;
}
}
return $tmp_array;
}
}
$Access = new ArrayAccessor();
$Access->setPrefix('Hi', 'Toto');
$MyTestArray['Hi']['Toto'] = 'Works';
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('Hi');
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('No');
var_dump ($Access->getFromPrefix($MyTestArray));
Result :
string(5) "Works"
array(1) {
["Toto"]=>
string(5) "Works"
}
NULL
In PHP we can do things like these:
Class Example {
...
}
$example = 'Example';
$object = new $example();
Or the use of variable variables:
$hour = 18;
$greets = array('Good morning','Good afternoon','Good evening');
$values = array(13,21,23);//people is sleeping at 23PM, so they don't greet.
$n = count($values);
$greet = 'greets';
for($i=0;$i<$n;$i++){
if($hour < $values[$i]){
echo 'hello, '.${$greet}[$i];
break;
}
}
And others..
I wonder if it would be possible to access directly to a specific index of a multidimensional array in a similar way. Something like:
$array = array(...); //multidimensional array.
$position = '[0][4][3]';
print_r($array$position);
Thanks in advance.
UPDATE
I'm so sorry because I finished my question in a wrong way.
I need to set the multimesional array and add a value. i.e:
$array$position = $data;
You could implement it yourself with a custom function:
function getValueFromMultiDimensionalArray( array $array, string $key )
{
$keys = explode('][', $key);
$value = $array;
foreach ($keys as $theKey) {
// remove the opening or closing bracket if present
$theKey = str_replace([ '[', ']' ], '', $theKey);
if (!isset($value[$theKey])) {
return null;
}
$value = $value[$theKey];
}
return $value;
}
You can define path as dot separated , check the following solution
function getValueByKey($a,$p){
$c = $a;
foreach(explode('.',$p) as $v){
if(!array_key_exists($v, $c)) return null;
$c = $c[$v];
}
return $c;
}
You can use this function as
$path = '1.2.3.0';
$indexValue = getValueByKey($array, $path);
Nope, this is not possible.
The only thing you can do is to implement ArrayAccess interface, which allows to access instances with [] operator. But you will have to define the logic yourself.
class MyClass implements ArrayAccess
{
...
}
$x = new MyClass([0=>[4=>[3=>'hello world']]]);
$position = '[0][4][3]';
echo $x[$position]; //hello world
I don't want to echo string if before string is similar to current string. Let's say our strings are,
$strings = array("software","software","game","antivirus");
My difference function,
function ($val1,$val2) {
similar_text($val1,$val2,$percent);
if ($percent>83) {
// should not echo. But don't know how to do.
}
}
But I don't know how can I do it. I guess it should be with using for each.
Try something like this:
$strings = array("software","software","game","antivirus");
$lastString = '';
foreach ($strings as $string) {
similar_text($lastString, $string, $percent);
if ($percent < 83) {
echo "$string<br />";
$lastString = $string;
}
}
If you don't understand some part of it, leave a comment and I will clarify.
Edit:
I moved the $lastString = $string; inside the condition.
Consider the following list of strings:
$strings = array("software","sofware","sofwart","ofwart","fwart","wart","warts");
Leaving the $lastString assignment outside of the loop would only print software even though lots of the words are very very different software they are not so different from the previous word.
Moving it inside actually gives the output :
software
sofwart
wart
$strings = array("software","software","game","antivirus");
$previous = '';
foreach ($strings as $string) {
if ($string===$previous) {
continue;
} else {
echo $string;
$previous = $string;
}
}
But I think it's better to do it with for like this (it should be faster):
$strings = array("software","software","game","antivirus");
$num = count($strings);
for ($i=0;$i<$num;$i++) {
if ($strings[$i]===$strings[$i-1] && $i!==0) {
continue;
} else {
echo $strings[$i];
}
}
Btw I totally did't get what the $percent means..
An approach using array_filter() (assumes >= 5.3):
$strings = array('software', 'software', 'game', 'antivirus');
$filtered = array_filter($strings, function($curr) {
static $prev;
similar_text($prev, $curr, $percent);
$prev = $curr;
if ($percent < 83) {
return $curr;
}
});
print_r($filtered);
Yields:
Array
(
[0] => software
[2] => game
[3] => antivirus
)
Hope this helps. Actually, I never knew about similar_text() until now. Pretty interesting function. Thanks :)
I have a simple associative array:
$ar = array( 1=>'foo', 2=>'bar', 5=>'foobar', 8=>'barfoo' )
I need to efficiently find holes in the keys. The keys are guaranteed to be integers.
findHole($ar)
> 0
findHole($ar,1)
> 3
findHole($ar,5)
> 6
what is the easiest way to do this?
Try this:
function findHole($array, $key=0) {
while (array_key_exists($key, $array)) {
$key++;
}
return $key;
}
The desired behavior of your findHole function isn't 100% clear to me, but the following code snippet will give you an array that has all the "missing" indexes.
$ar = array( 1=>'foo', 2=>'bar', 5=>'foobar', 8=>'barfoo' );
$keys = array_keys($ar);
$missing_indexes = array_diff(range(0,max($keys)), $keys);
print_r($missing_indexes);
Depending on your use case this may or may not be less efficient. It's using multiple function calls and arrays are passed around by value by default, but those functions are operating at native code speeds, while solutions using loops are going to be running at PHP speed.
Use case, benchmark, etc.
All holes:
function GetHoles($arr)
{
$holes = array();
$max_value = max(array_keys($arr));
for($i = 0; $i < $max_value; $i++)
{
if(!in_array($i, $keys)) $holes[] = $i;
}
return $holes;
}
if you just want to condense the array, try this:
function FlattenArray( $o )
{
$res = array();
foreach($o as $v)
{
$res = array_merge($res, FlattenArray($v));
}
return $res;
}
I've got a multidimensional associative array which includes an elements like
$data["status"]
$data["response"]["url"]
$data["entry"]["0"]["text"]
I've got a strings like:
$string = 'data["status"]';
$string = 'data["response"]["url"]';
$string = 'data["entry"]["0"]["text"]';
How can I convert the strings into a variable to access the proper array element? This method will need to work across any array at any of the dimensions.
PHP's variable variables will help you out here. You can use them by prefixing the variable with another dollar sign:
$foo = "Hello, world!";
$bar = "foo";
echo $$bar; // outputs "Hello, world!"
Quick and dirty:
echo eval('return $'. $string . ';');
Of course the input string would need to be be sanitized first.
If you don't like quick and dirty... then this will work too and it doesn't require eval which makes even me cringe.
It does, however, make assumptions about the string format:
<?php
$data['response'] = array(
'url' => 'http://www.testing.com'
);
function extract_data($string) {
global $data;
$found_matches = preg_match_all('/\[\"([a-z]+)\"\]/', $string, $matches);
if (!$found_matches) {
return null;
}
$current_data = $data;
foreach ($matches[1] as $name) {
if (key_exists($name, $current_data)) {
$current_data = $current_data[$name];
} else {
return null;
}
}
return $current_data;
}
echo extract_data('data["response"]["url"]');
?>
This can be done in a much simpler way. All you have to do is think about what function PHP provides that creates variables.
$string = 'myvariable';
extract(array($string => $string));
echo $myvariable;
done!
You can also use curly braces (complex variable notation) to do some tricks:
$h = 'Happy';
$n = 'New';
$y = 'Year';
$wish = ${$h.$n.$y};
echo $wish;
Found this on the Variable variables page:
function VariableArray($data, $string) {
preg_match_all('/\[([^\]]*)\]/', $string, $arr_matches, PREG_PATTERN_ORDER);
$return = $arr;
foreach($arr_matches[1] as $dimension) { $return = $return[$dimension]; }
return $return;
}
I was struggling with that as well,
I had this :
$user = array('a'=>'alber', 'b'=>'brad'...);
$array_name = 'user';
and I was wondering how to get into albert.
at first I tried
$value_for_a = $$array_name['a']; // this dosen't work
then
eval('return $'.$array_name['a'].';'); // this dosen't work, maybe the hoster block eval which is very common
then finally I tried the stupid thing:
$array_temp=$$array_name;
$value_for_a = $array_temp['a'];
and this just worked Perfect!
wisdom, do it simple do it stupid.
I hope this answers your question
You would access them like:
print $$string;
You can pass by reference with the operator &. So in your example you'll have something like this
$string = &$data["status"];
$string = &$data["response"]["url"];
$string = &$data["entry"]["0"]["text"];
Otherwise you need to do something like this:
$titular = array();
for ($r = 1; $r < $rooms + 1; $r ++)
{
$title = "titular_title_$r";
$firstName = "titular_firstName_$r";
$lastName = "titular_lastName_$r";
$phone = "titular_phone_$r";
$email = "titular_email_$r";
$bedType = "bedType_$r";
$smoker = "smoker_$r";
$titular[] = array(
"title" => $$title,
"first_name" => $$firstName,
"last_name" => $$lastName,
"phone" => $$phone,
"email" => $$email,
"bedType" => $$bedType,
"smoker" => $$smoker
);
}
There are native PHP function for this:
use http://php.net/manual/ru/function.parse-str.php (parse_str()).
don't forget to clean up the string from '"' before parsing.
Perhaps this option is also suitable:
$data["entry"]["0"]["text"];
$string = 'data["entry"]["0"]["text"]';
function getIn($arr, $params)
{
if(!is_array($arr)) {
return null;
}
if (array_key_exists($params[0], $arr) && count($params) > 1) {
$bf = $params[0];
array_shift($params);
return getIn($arr[$bf], $params);
} elseif (array_key_exists($params[0], $arr) && count($params) == 1) {
return $arr[$params[0]];
} else {
return null;
}
}
preg_match_all('/(?:(\w{1,}|\d))/', $string, $arr_matches, PREG_PATTERN_ORDER);
array_shift($arr_matches[0]);
print_r(getIn($data, $arr_matches[0]));
P.s. it's work for me.