Currently I am attempting to call a multidimensional array, using a string as a key or keys. I would like to use the following code, but I think the key is being interpreted as a string. Any solution?
$data= [];
$data['volvo'] = "nice whip";
$test = "['volvo']";
$data['drivers']['mike'] = "decent";
$test2 = "['drivers']['mike']";
echo $data$test; // should read 'nice whip'
echo $data$test2; // should read 'decent'
You just use the variable (which should just be the string and not PHP syntax) in place of the string literal.
$cars = [];
$cars['volvo'] = 'nice whip';
$test = 'volvo';
echo $cars[$test];
If you need a dynamic array access solution, you could also write a function, which does the actual array access like this:
function path($array, $path) {
$path = is_array($path) ? $path : explode('.', $path);
$current = $array;
while (count($path)) {
$seg = array_shift($path);
if (!isset($current[$seg])) throw new Exception('Invalid path segment: ' . $seg);
$current = $current[$seg];
}
return $current;
}
In your case, this would look like this
echo path($data, 'volvo');
echo path($data, 'drivers.mike');
or
echo path($data, ['volvo']);
echo path($data, ['drivers', 'mike']);
The problem is you can't pass multiple levels in one string like that. (If so, PHP would have to start looking for code fragments inside string array keys. And how would it know whether to interpret them as fragments and then split the string key up, or keep treating it as one string??)
Alt 1
One solution is to change the structure of $data, and make it a single level array. Then you supply keys for all the levels needed to find your data, joined together as a string. You would of course need to find a separator that works in your case. If the keys are plain strings then something simple like underscore should work just fine. Also, this wouldn't change the structure of your database, just the way data is stored.
function getDbItem($keys) {
// Use this to get the "old version" of the key back. (I.e it's the same data)
$joinedKey = "['".implode("'],['", $keys)."']";
$joinedKey = implode('_', $keys);
return $data[$joinedKey];
}
// Example
$data = [
'volvo' => 'nice whip',
'drivers_mike' => 'decent'
];
var_dump(getDbItem(['drivers', 'mike'])); // string(6) "decent"
Alt 2
Another way is to not change number of levels in $data, but simply traverse it using the keys passed in:
$tgt = $data;
foreach($keys as $key) {
if (array_key_exists($key, $tgt)) {
$tgt = $tgt[$key];
}
else {
// Non existing key. Handle properly.
}
}
// Example
$keys = ['drivers', 'mike'];
// run the above code
var_dump($tgt); // string(6) "decent"
Related
I need to access specific indexes and keys of given arrays using eval, but somehow I cannot do so when my "path" is specified by a String. The code and content I am trying to access is bellow.
$final_eval = eval('
var_dump($contents->beneficiarios[0]->nomeOperadora);//returns ok value 'Operadora 123'
var_dump($contents->$temp_eval);//doesnt work when $temp_eval's value is 'beneficiarios[0]->nomeOperadora'
return $contents->$temp_eval;
');
Now if I use $temp_eval with value 'mensagem', without quotes, it works fine for the specified json key. (returns '2 users found').
The only problem seems to be when my "path" specifies an array index, as I need to access a value inside given array.
Bellow is the $contents value (I already decoded it before trying to access in my code):
{
"sucesso": true,
"mensagem": "2 users found",
"beneficiarios": [
{
"nomeOperadora": "Operadora 123",
"codigoBeneficiario": "XXAADD123"
},
{
"nomeOperadora": "Operadora 456",
"codigoBeneficiario": "XXBBEE843"
}
]
}
I need to access values such as in my first var_dump from the first code spinnet, json_key[index]->json_key, passing their "path" dinamically.
Any suggestions? Thanks in advance!
As Jeto and Jerson questioned, eval is indeed not necessary. I have tried using it because I get each object's path dynamically, and as my first approach it seemed correctly.
Anyway, the problem is that passing a string that contains the denotation '->' or '[index]' doesn't correctly access the object's property.
My solution is to explode the string and then loop as given bellow:
$explode = explode('->', '$contents->beneficiarios[0]->nomeOperadora');
$i = 0;
foreach($explode as $item):
$has_array_index = false;
$array_index = null;
$has_array_index = preg_match("/\[(.*?)\]/", $item, $array_index, PREG_UNMATCHED_AS_NULL);
if($has_array_index):
$item = str_replace($array_index[0], '', $item);
$array_index = substr($array_index[0], 1, -1);
endif;
if($i == 0):
if($has_array_index)
$final_eval = $contents->$item[$array_index];
else
$final_eval = $contents->$item;
else:
if($has_array_index)
$final_eval = $final_eval->$item[$array_index];
else
$final_eval = $final_eval->$item;
endif;
$i++;
endforeach;
It may not be the prettiest solution, but it's good enough to move on to more important things for now.
I'm trying to execute variable which part of it is a string.
Here it is:
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = "['index_1']['index_2']";
I tried to do it in following ways:
// #1
$myValue = $row{$pattern};
// #2
$myValue = eval("$row$pattern");
I also trying to get it working with variable variable, but not successful.
Any tips, how should I did it? Or myabe there is other way. I don't know how may look array, but I have only name of key indexes (provided by user), this is: index_1, index_2
You could use eval but that would be quite risky since you say the values come from user input. In that case, the best way might be to parse the string and extract the keys. Something like this should work:
$pattern = "['index_1']['index_2']";
preg_match('/\[\'(.*)\'\]\[\'(.*)\'\]/', $pattern, $matches);
if (count($matches) === 3) {
$v = $row[$matches[1]][$matches[2]];
var_dump($v);
} else {
echo 'Not found';
}
This can help -
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = "['index_1']['index_2']";
$pattern = explode("']['", $pattern); // extract the keys
foreach($pattern as $key) {
$key = str_replace(array("['", "']"), '', $key); // remove []s
if (isset($row[$key])) { // check if exists
$row = $row[$key]; // store the value
}
}
var_dump($row);
Storing the $row in temporary variable required if used further.
Output
string(8) "my-value"
If you always receive two indexes then the solution is quite straight forward,
$index_1 = 'index_1';// set user input for index 1 here
$index_2 = 'index_2';// set user input for index 2 here
if (isset($row[$index_1][$index_2])) {
$myValue = $row[$index_1][$index_2];
} else {
// you can handle indexes that don't exist here....
}
If the submitted indexes aren't always a pair then it will be possible but I will need to update my answer.
As eval is not safe, only when you know what you are ding.
$myValue = eval("$row$pattern"); will assign the value you want to $myValue, you can add use return to make eval return the value you want.
here is the code that use eval, use it in caution.
demo here.
<?php
$row = array(
'index_1' => array(
'index_2' => 'my-value'
)
);
$pattern = 'return $row[\'index_1\'][\'index_2\'];';
$myValue = eval($pattern);
echo $myValue;
I'm not sure how to call this, and I can't find what I'm looking for because I must be looking for the wrong keywords, so even the right search term would help me out here:
I have a $map array and a $data array. The $data array is a dynamic array based on a xml that is parsed. Simplified Example:
$data = array('a' => array(0=> array('hello'=>'I want this data')));
$map = array('something' => 'a.0.hello');
Now I'd like to set $test to the value of $data['a']['0']['hello'] by somehow navigating there using $map['something']. The idea behind this is to create a mapping array so that no code changes are required if the xml format is to be changed, only the mapping array. Any help in the good direction is very much appreciated :)
// Set pointer at top of the array
$path = &$data;
// Asume that path is joined by points
foreach (explode('.', $map['something']) as $p)
// Make a next step
$path = &$path[$p];
echo $path; // I want this data
There's not really a good way to programmatically access nested keys in arrays in PHP (or any other language I can think of, actually).
function getDeepValue(&$arr, $keys) {
if (count($keys) === 0)
return $arr;
else
return getDeepValue($arr[$keys[0]], array_slice($keys, 1));
}
$data = ['a' => [0=> ['hello'=>'I want this data']]];
$map = ['something' => getDeepValue($data, ['a', '0', 'hello'])];
var_dump($map);
// array(1) {
// ["something"]=>
// string(16) "I want this data"
// }
If you want to use the string of keys, just use
getDeepValue($arr, explode('.', 'a.0.hello'))
If that's a common operation you have to do, you could add another layer of abstraction that accepts string-based lookup of deep values.
I'm getting this error with my current PHP code:
Notice: TO id was not an integer: 1, 2. 1) APNS::queueMessage ->
How can I convert to an array of strings to an array of integers like in this other question: ID not integer... EasyAPNS ?
I'm basically trying to pass ids (from my database,) to newMessage() like this Apple example:
// SEND MESSAGE TO MORE THAN ONE USER
// $apns->newMessage(array(1,3,4,5,8,15,16));
// ($destination contain a string with the Ids like "1,2,3")
Here is my code below:
if (isset($destination))
{
//$destination = 1,2,..
$dest = explode(",", $destination);
if (isset($time))
{
$apns->newMessage($dest, $time);
}
else
{
$apns->newMessage($dest);
}
$apns->addMessageAlert($message);
$apns->addMessageBadge($badge);
$apns->addMessageSound('bingbong.aiff');
$apns->queueMessage();
header("location:$url/index.php?success=1");
}
I would create a wrapper function that accepts an array, and then call it.
function newMessageArray($array) {
foreach ($array as $element) {
$apns->newMessage($element);
}
}
This way, you can call newMessageArray() with an array of integers, such as array(1,2,3,4,5), and they will all be sent.
Also, you should change the variable names (from $array and $element) to something more meaningful. I don't know what you're trying to do, so I wasn't sure what names to use.
Your Question is not clear, It's only a guess work.
It seems to be error in convert integer, try
$dest = explode(",", $destination);
$destArray = array();
foreach($dest as $key => $val) {
$destArray[$key] = intval($val);
}
if (isset($time))
{
$apns->newMessage($destArray, $time);
}
else
{
$apns->newMessage($destArray);
}
Convert where the string is not integer using 'intval'.
I believe what you may be looking for is how to do this:
You have ids in your database table, right? And you are trying to get multiple ids into an array so that the array can be used in $apns->newMessage() call, right? (I checked the source for this...) But, the ids are somehow coming over as strings instead of ints.
So, you probably want to just make sure that the new array is made up of ints, like this:
function to_int($x) {
return (int)$x;
}
$dest = array_map("to_int", $dest);
There are probably other ways to do this, but this way, you at least know that you have int variables in that array. Hope that helps!
I have some code that grabs some rows from a table and I want to make an associative array in PHP that will be like [row_id] => row_title. This will then be used to populate a select list. The problem is, the key, unless I include a string in it, always reverts to an ordered number starting with 0. If I add a string in with the key, then the key retains the ID that I want. But obviously I don't want the string in the key.
Here's my code:
public static function select_array(){
$courses = ORM::factory('course')->order_by('title')->find_all();
$out = array();
foreach($courses as $c){
$out[$c->id] = $c->title;
}
return $out;
}
The $c->id should be the id from the database, but PHP is overriding this with a count number. If I do this:
public static function select_array(){
$courses = ORM::factory('course')->order_by('title')->find_all();
$out = array();
foreach($courses as $c){
$test = "." . $c->id;
$out[$test] = $c->title;
}
return $out;
}
Then the key will include the correct ID, but with a "." in front... I've tried using (string)$c->id but no luck with that either. I've also tried setting $test as " " . $c->id and then trimming it, but that doesn't work, and it's just a weird hacky attempt anyway.
Hope that makes sense. My question: How to simply tell the key to be a specific number?
Can you var_dump $courses before the foreach statement and $out before the return?
Well if it's overwriting it, I don't see why. Try this...
foreach($courses as $c){
$test = "" . $c->id;
$out[(int)$test] = $c->title;
}
The first snippet looks like it should work the way you want. Assuming that $c->id doesn't produce an ordered list of ints, are you sorting the array after retrieving from select_array()? Have you tried var_dump()'ng $out after the foreach and before the return statement?
If converting to a string solves the problem, try something like
$out[(string)$c->id] = $c->title;