Having a string like
12345.find_user.find_last_name
how can i split at the charachter "." and convert it to a function-call:
find_last_name(find_user(12345));
and so on....could be of N-Elements (n-functions to run)....how do i do this effectivly, performance-wise also?
Edit, here is the solution based on your replies
thanks Gaurav for your great help. Here is my complete solution based on yours:
i protected the foreach with if(function_exists($function)){ to protect the whole thing from fatal php errors, and i added a complete example:
$mystring = '12345.find_user.find_last_name';
convert_string_to_functions($mystring);
function convert_string_to_functions($mystring){
$functions = explode('.', $mystring);
$arg = array_shift($functions);
foreach($functions as $function){
if(function_exists($function)){
$arg = $function($arg);
} else {
echo 'Function '.$function.' Not found';
}
}
echo $arg;
}
function find_last_name($mystring=''){
return $mystring.' i am function find_last_name';
}
function find_user($mystring=''){
return $mystring.' i am function find_user';
}
$string = '12345.find_user.find_last_name';
$functions = explode('.', $string);
$arg = array_shift($functions);
foreach($functions as $function){
$arg = $function($arg);
}
echo $arg;
Related
I have a string that comes from a db: $text=
parameter1=value1
parameter2=value2
otherparemeter=othervalue
I need a function to replace an parameter with a new value, but if parameter does not exist; must to add to string;
Example: updatestring ($text,"parameter1","newvalue"):
Result:
parameter1=newvalue
parameter2=value2
otherparemeter=othervalue
Or: updatestring ($text,"myparameter","myvalue"):
Result:
parameter1=value1
parameter2=value2
otherparemeter=othervalue
myparameter=myvalue
thanks !
Given the format of your input parse_ini_string should work to parse out the data into a structure that can easily be altered and reformated.
Maybe something like this:
$a =<<<EOF
parameter1=value1
parameter2=value2
otherparemeter=othervalue
EOF;
function replacevalue($text, $k, $v){
$dat = parse_ini_string($text);
$ret = "";
if(isset($dat[$k])){
$dat[$k] = $v;
foreach($dat as $prop=>$val){
$ret.= $prop."=".$val."\n";
}
return $ret;
}
}
echo replacevalue($a, "parameter1", "Hello World");
this might work if every paramater and value are on its own line
function updatestring($text, $param1, $param2)
{
if( stristr($text, $param1.'=') ) $text = preg_replace("`$param1=.*\n`iU", "$param1=$param2".PHP_EOL, $text);
else $text .= PHP_EOL.$param1.'='.$param2;
return $text;
}
thanks #Orangepill; I've corrected your function; now it's working
function replacevalue($text, $k, $v){
$dat = parse_ini_string($text);
$ret = "";
if(isset($dat[$k])){
$dat[$k] = $v;
} else {
$dat[$k] = $v;
}
foreach($dat as $prop=>$val){
$ret.= $prop."=".$val."\n";
}
return $ret;
}
I have a function called get_config() and an array called $config.
I call the function by using get_config('site.name') and am looking for a way to return the value of $config so for this example, the function should return $config['site']['name'].
I'm nearly pulling my hair out - trying not to use eval()! Any ideas?
EDIT: So far I have:
function get_config($item)
{
global $config;
$item_config = '';
$item_path = '';
foreach(explode('.', $item) as $item_part)
{
$item_path .= $item."][";
$item = $config.{rtrim($item_path, "][")};
}
return $item;
}
This should work:
function get_config($config, $string) {
$keys = explode('.', $string);
$current = $config;
foreach($keys as $key) {
if(!is_array($current) || !array_key_exists($key, $current)) {
throw new Exception('index ' . $string . ' was not found');
}
$current = $current[$key];
}
return $current;
}
you could try something like...
function get_config($item)
{
global $config;
return $config[{str_replace('.','][',$item)}];
}
Inside your get_config function, you can parse the string using explode function in php
function get_config($data){
$pieces = explode(".", $data);
return $config[$pieces[0]][$pieces[1]];
}
If I had an array such as:
testarray = array('foo'=>34, 'bar'=>array(1, 2, 3));
How would I go about converting a string such as testarray[bar][0] to find the value its describing?
Well, you can do something like this (Not the prettiest, but far safer than eval)...:
$string = "testarray[bar][0]";
$variableBlock = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
$regex = '/^('.$variableBlock.')((\[\w+\])*)$/';
if (preg_match($regex, $string, $match)) {
$variableName = $match[1]; // "testarray"
if (!isset($$variableName)) {
//Error, the variable does not exist
return null;
} else {
$array = $$variableName;
if (preg_match_all('/\[(\w+)\]/', $match[2], $matches)) {
foreach ($matches[1] as $match) {
if (!is_array($array)) {
$array = null;
break;
}
$array = isset($array[$match]) ? $array[$match] : null;
}
}
return $array;
}
} else {
//error, not in correct format
}
You could use PHP's eval function.
http://php.net/manual/en/function.eval.php
However, make absolutely sure the input is sanitized!
Cheers
I've been trying to think of a way to dynamically return property values for a class using __call instead of creating a slew of functions whose only purpose would be to return those values. The idea I have is to be able to request ( for example ) $this->fetch_PersonFirstName() and have the class check if $this->person["first_name"] is set and return the value. Another example would be calling $this->fetch_BookGenreTitle() and have the class return the value of $this->book["genre"]["title"]. I know something like this would have to do a bit of checking in order for it to automatically determine that, for example, since $this->book["genre_title"] doesn't exist, then it should check for $this->book["genre"]["title"].
So far I've come up with code that ( for some reason ) works for returning the values of an array ( such as my person example ) but my problem quickly develops when I try to return the values of a multidimensional array ( such as with my above book example ). Bare in mind, I'm still trying to think of a way for the __call method to check for the existence of one, and if it doesn't exist, then the other.
Please, throw me a line here. I've been banging my head against the wall trying to figure this out and it's killing me.
<?php
class Test
{
protected $person;
protected $book;
public function __construct()
{
$this->person["first_name"] = "John Smith";
$this->book["genre"]["title"] = "Suspense";
}
public function __call($method, $args)
{
$args = implode(", ", $args);
if (preg_match("/^fetch_([A-Z]{1,}[a-z]{1,})(.*)?/", $method, $match))
{
print_r($match);
echo "<br><br>";
$property = strtolower($match[1]);
$indexes = $match[2];
if (property_exists("Test", $property))
{
if ($indexes)
{
$indexes = preg_split("/(?<=[a-z])(?=[A-Z])/", $indexes);
$num_indexes = count($indexes);
$count_indexes = 1;
for ($count=0; $count<$num_indexes; $count++)
{
$record = strtolower($indexes[$count]);
$index .= $record;
$array .= "{$record}";
$var_index = $index;
$var_array = $array;
echo $var_index." {$count}<br>";
echo $var_array." {$count}<br>";
//print_r($this->{$property}{$var_array});
if ($count_indexes == $num_indexes)
{
if (isset($this->{$property}{$var_index}))
{
return $this->{$property}{$var_index};
}
else
{
return $this->{$property}{$var_array};
}
}
else
{
$index .= "_";
}
$count_indexes++;
}
echo "<br><br>";
}
else
{
return $this->{$property};
}
}
}
}
}
?>
<?php
$test = new Test();
echo $test->fetch_PersonFirstName();
echo "<br><br>";
echo $test->fetch_BookGenreTitle();
?>
Thanks again folks. I think I finally have my solution, which works for multidimensional arrays or any depth and accounts for determining whether a property is, for example $this->book["genre_title"] or $this->book["genre"]["title"] :)
I'm posting the code below as someone else may randomly find it useful in the future
<?php
class Test
{
protected $person;
protected $book;
public function __construct()
{
$this->person["first_name"] = "John Smith";
$this->book["genre"]["title"] = "Suspense";
}
public function __get($var)
{
if (preg_match_all("/([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)/", $var, $matches))
{
$matches = $matches[1];
$property = strtolower($matches[0]);
if (property_exists($this, $property))
{
unset($matches[0]);
$matches = array_values($matches);
$num_matches = count($matches);
$var = &$this->{$property};
if (!$num_matches)
{
return $var;
}
else
{
foreach($matches as &$match)
{
$match = strtolower($match);
$index .= $match;
if ($probe = $this->iterateArray($var, $index))
{
$var = $probe;
unset($index);
}
elseif ($probe = $this->iterateArray($var, $index))
{
$var = $probe;
}
else
{
$index .= "_";
}
}
return $var;
}
}
}
}
public function iterateArray($var, $index)
{
if (array_key_exists($index, $var))
{
return $var[$index];
}
else
{
return false;
}
}
}
?>
<?php
$test = new Test();
echo $test->PersonFirstName;
echo "<br><br>";
echo $test->BookGenreTitle;
?>
There's more than likely some ways to improve/streamline the code, in which case anyone wanting to do so is more than welcome to post an improved version.
Given "BookGenreTitle" :
Use some sort of regex to separate "Book", "Genre", and "Title"
property_exists($this, "Book")
array_key_exists("genre", $this->book)
If key exists, return $this->book["genre"]
If key doesn't exist, array_key_exists("genre_title", $this->book)
If key exists, return $this->book["genre_title"]
If key doesn't exist, array_key_exists("genre", $this->book) && array_key_exists("title", $this->book["genre"])
Keep going
There's probably a way to use a loop or some sort of recursion instead of hard-coding the maximum depth, but I won't get into that now...
Oh, and as the other poster said, what you want is property overloading (__get and __set).
You need to take a look at property overloading, not method overloading as you've already figured out in the question's title yourself.
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.