Find Item by key without using eval - php

I know that eval() is a horrible thing to use, but I couldn't think of a better way to do this.
I have the following method which I want to use to delete items from a multidimensional array, and it should delete the item if it exists.
public function delete(){
$keys = func_get_args();
$str = "";
foreach($keys as $key){
$str .= "['$key']";
}
eval("if(isset(\$_SESSION$str)){unset(\$_SESSION$str);}");
}
To use it I would make a call like so:
$obj->delete("one", "two", "three");
which would be the equivalent to this:
if(isset($_SESSION["one"]["two"]["three"])){
unset($_SESSION["one"]["two"]["three"]);
}
Is there a better way to do this than using eval()?

There is a function like that in Ouzo Goodies:
Arrays::removeNestedKey($_SESSION, ['one', 'two', 'three']);
If you don't want to include the lib, you can take a look at the source code and grab the function itself:
public static function removeNestedKey(array &$array, array $keys)
{
$key = array_shift($keys);
if (count($keys) == 0) {
unset($array[$key]);
} else {
self::removeNestedKey($array[$key], $keys);
}
}

This will achieve what you want:
function delete(){
$keys = func_get_args();
$ref = &$_SESSION;
for($x = 0; $x < sizeOf($keys)-1; $x++) {
$ref = &$ref[$keys[$x]];
}
unset($ref[$keys[sizeOf($keys)-1]]);
unset($ref);
}

Related

php access to specific position of multidimensional array by its keys and set it

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

PHP Function Array values not changing

Ive created a function that takes an array as a parameter and changes all values to 4, but it doesn't work and i don't understand why. Really bothering me, could use help thank you!
$cup3 = array (1,4,3,5,7,2);
roll($cup3);
print_r($cup3);
function roll($array)
{
foreach($array as &$value)
{
$value = 4;
}
return $array;
}
Output: (1,4,3,5,7,2) instead of all 4s
Either pass by reference &$array to edit $cup3 directly:
roll($cup3);
print_r($cup3);
function roll(&$array)
{
foreach($array as &$value)
{
$value = 4;
}
}
Or use the return from the function:
$cup3 = roll($cup3);
print_r($cup3);
function roll($array)
{
foreach($array as &$value)
{
$value = 4;
}
return $array;
}

PHP - dynamically add dimensions to array

I have a :
$value = "val";
I also have an array :
$keys = ['key1', 'key2', 'key3'...]
The keys in that array are dynamically generated, and can go from 2 to 10 or more entries.
My goal is getting this :
$array['key1']['key2']['key3']... = $value;
How can I do that ?
Thanks
The easiest, and least messy way (ie not using references) would be to use a recursive function:
function addArrayLevels(array $keys, array $target)
{
if ($keys) {
$key = array_shift($keys);
$target[$key] = addArrayLevels($keys, []);
}
return $target;
}
//usage
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, []);
It works as you can see here.
How it works is really quite simple:
if ($keys) {: if there's a key left to be added
$key = array_shift($keys); shift the first element from the array
$target[$key] = addArrayLevels($keys, []);: add the index to $target, and call the same function again with $keys (after having removed the first value). These recursive calls will go on until $keys is empty, and the function simply returns an empty array
The downsides:
Recursion can be tricky to get your head round at first, especially in complex functions, in code you didn't write, but document it well and you should be fine
The pro's:
It's more flexible (you can use $target as a sort of default/final assignment variable, with little effort (will add example below if I find the time)
No reference mess and risks to deal with
Example using adaptation of the function above to assign value at "lowest" level:
function addArrayLevels(array $keys, $value)
{
$return = [];
$key = array_shift($keys);
if ($keys) {
$return[$key] = addArrayLevels($keys, $value);
} else {
$return[$key] = $value;
}
return $return;
}
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, 'innerValue');
var_dump($subArrays);
Demo
I don't think that there is built-in function for that but you can do that with simple foreach and references.
$newArray = [];
$keys = ['key1', 'key2', 'key3'];
$reference =& $newArray;
foreach ($keys as $key) {
$reference[$key] = [];
$reference =& $reference[$key];
}
unset($reference);
var_dump($newArray);

Process an array in a function, with external formatting

I want to pass an array to a function and iterate through it in this function. But I would like to be able to change the way the single entries are displayed.
Suppose I have an array of complicated objects:
$items = array($one, $two, $three);
Right now I do:
$entries = array();
foreach($items as $item) {
$entries[] = create_li($item["title"], pretty_print($item["date"]));
}
$list = wrap_in_ul($entries);
I would like to do the above in one line:
$list = create_ul($items, $item["title"], pretty_print($item["date"]));
Any chance of doing that as of PHP4? Be creative!
from my understanding, you're looking for an "inject" type iterator with a functional parameter. In php, inject iterator is array_reduce, unfortunately it's broken, so you have to write your own, for example
function array_inject($ary, $func, $acc) {
foreach($ary as $item)
$acc = $func($acc, $item);
return $acc;
}
define a callback function that processes each item and returns accumulator value:
function boldify($list, $item) {
return $list .= "<strong>$item</strong>";
}
the rest is easy:
$items = array('foo', 'bar', 'baz');
$res = array_inject($items, 'boldify', '');
print_r($res);
You could use callbacks:
function item_title($item) {
return $item['title'];
}
function item_date($item) {
return $item['date'];
}
function prettyprint_item_date($item) {
return pretty_print($item['date']);
}
function create_ul($items, $contentf='item_date', $titlef='item_title') {
$entries = array();
foreach($items as $item) {
$title = call_user_func($titlef, $item);
$content = call_user_func($contentf, $item);
$entries[] = create_li($title, $content);
}
return wrap_in_ul($entries);
}
...
$list = create_ul($items, 'prettyprint_item_date');
PHP 5.3 would be a big win here, with its support for anonymous functions.

PHP array as variable name

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));

Categories