PHP - Function name from variable - php

Okay, I've found a possible solution for this, but for some reason, I can't make it work in my application. Apparently, if I have a variable which contains a name function, I could use
<?php echo $variable(); ?>
to output the function with the same name.
I'm using Codeigniter. It has a function in its Form helper to output a text field, which is
<?php form_input(); ?>
I have a variable
<?php $instance['taxon_field'] = 'form_input'; ?>
If I echo out this variable, I do get the needed value, 'form_input'. However, as soon as I try to echo
$instance['taxon_field']()
I get a warning:
Message: Illegal string offset 'taxon_field'
and a fatal error:
Call to undefined function p()
I am really clueless here, because echoing only the variable gives 'form_input', but echoing $variable() only gives 'p'.
Where am I doing wrong?

The actual problem here is that $instance is not an array, but a string. Judging from the error message, it's a string whose value starts with p.
The syntax $var[$key] is used not only to access array elements but also to index into strings, where $var[0] would be the first character (actually, byte) of $var etc. If $instance is a string and you write $instance['taxon_field'] then PHP will try to convert 'taxon_field' to an integer in order to index into the string. This results in 0 as per the usual conversion rules, so the whole expression gets you the first letter of the string.
Assuming that the string starts with p it's then pretty obvious why it tries to call a function with that name.

Use call_user_func()
call_user_func($instance['taxon_field']);

The confusion created is actually my own fault because I failed to provide some aditional information which I thought was not important, but turned out to be crutial. My $instance[] array is actually a result of a foreach loop (two of them, to be precise) and is a part of a bigger multidimensional array. The actual code is more complicated, but I'll try to represent it right:
<?php
$bigger_array = array(
0 => array(
'field_one' => 'value_one',
'field_two' => 'value_two',
'field_three' => 'new_function'
),
1 => array(
'field_one' => 'new_value_one',
'field_two' => 'new_value_two',
'field_three' => 'echo'
)
);
function new_function()
{
echo 'New function called.';
}
foreach($bigger_array as $instance)
{
$name = $instance['field_three'];
$name('Hello World!');
}
?>
This will output the following:
New function called.
Fatal error: Call to undefined function echo() in /opt/lampp/htdocs/bla.php on line 69
In other words, the newly defined function works fine, but the built-in 'echo' doesn't.
This is actually not my original problem, this is something that I've encountered while trying to debug the initial issue. And the original problem is that creating a function from a single-dimensional array works okay. whereas creating a function from a multi-dimensional array within a foreach loop transforms the array into a string with the value of its last member.
Now, I'm still not really able to fully answer my question, but I think information I'm giving could lead to a solution. In the simplified example that I gave here, why am I getting the message that echo() function is not defined, while the new function works fine?

Related

PHP optional parameter

I'm kinda confused about optional parameters, or setting a parameter within the function in general. So I found this example:
<?php
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");
?>
and I don't understand why echo makecoffe("espresso") returns espresso and not cappuccino. Wouldn't espresso be overwritten when calling the method? In my head $type would first be espresso but would then be set to cappuccino since it happens after calling the method. It's kind of hard to explain what I mean, but does $type = "cappuccino" only get called when there's no parameter or why does this happen? Same with
function makecoffee($type = null)
{
}
echo makecoffe("espresso");
why would this return espresso and not null even though type would be set to null when calling the function?
Good example to inform you how exactly the php parameters in functions works, would be the func_get_args() which returns all passed arguments to function.
And this will be our example function.
function foo($example = 'default')
{
print_r(func_get_args());
}
Now we can check if any argument was passed to function.
What happens if we don't pass any argument?
foo();
// Output
Array
(
)
We know that function was called without any argument because output array is empty.
And that is the moment where default value is used for our function parameter. So finally the value for $example parameter will be equal to 'default'
Now we will try to pass 2 arguments to function.
foo('example', 'unnecessary');
// Output
Array
(
[0] => example
[1] => unnecessary
)
From this example we can deduce that we can pass any amount of arguments without seeing an exception. This is one of php features.
But which was passed to $example parameter?
As php docs informs.
The arguments are evaluated from left to right.
The left side for our example is the value from an array with index 0 and the right side is the last element with (actually index 1)
So, under $example we well have 'example' value.
In defaults, the second argument will be ignored because our function doesn't have corresponding second parameter.
What if we pass null as a argument?
This may be tricky because we can imagine that function called with null as a argument will affect on our function as function called without any arguments.
Nothing more wrong.
foo(null);
// Output
Array
(
[0] =>
)
Now you should see that. Despite the fact that our argument was null, value was passed into our function and overwrited default 'example' value for parameter. Finally $example parameter will be equal to null.
That's because the $param = 'value' bit in the function declaration is not executed every time the function is called.
It only comes into play if you don't pass a value for that parameter.
Instead of reading it as a literal assignment PHP does something along the lines of the following under the hood whenever it enters your function.
if true === $param holds no value
$param = 'value'
endif
In other words, $param = 'value' is not a literal expression within the context of the language but rather a language construct to define the desired behaviour of implementing fallback default values.
Edit: Note that the snippet above is deliberately just pseudo code as it's tricky to accurately express what's going using PHP on once PHP has been compiled. See the comments for more info.

Unable to get dynamic PHP's Object value using PHP variable

PHP is unable to get the value for dynamic object prepared as:
$abc->{$dynamic_object_pattern}
Where the value of the variable $dynamic_object_pattern is, json->{'data_1'}->{'value'}
For me, PHP 7.1 is understanding the statically defined pattern like below, and fetching the value as it should:
$abc->json->{'data_1'}->{'value'}
But not when I put the whole portion into a variable and then try to get its value. I Tried,
$abc->{$dynamic_object_pattern} and $abc->$dynamic_object_pattern
both ways, but no solution yet.
The error comes is Notice: Undefined property: stdClass::$json->{'data_1'}->{'value'}
I'm attempting an answer without seeing your JSON data
Here you say :
But not when I put the whole portion into a variable and then try to
get its value
From that line alone it sounds like you are trying to get value from a string rather than array. If you put the whole portion into a variable, PHP will interpret it as string. Make sure you add array() before newly created variable.
Natural array :
$array = array();
Now a string
$variable = $array;
Convert string to array
$new_array = array($variable);
Also, have you tried decoding?
// decode
$response = json_decode($new_array, true);
//print out
var_export(array_unique(array($response)));

PHP: Why should only variables be passed by reference?

If you are a PHP developer you most probably have seen the following notice:
Notice: Only variables should be passed by reference in /somefile.php
on line xxx
(Problem extensivley treated in Only variables should be passed by reference)
Example throwing notice:
$string = "hi-dude";
echo end(explode('-', $string));
Working example:
$string = "hi-dude";
$strings = explode('-', $string);
echo end($strings);
Explanation:
Only real variables may be passed by reference, not functions which are returning the correct variable.
However I can not think of a good reason why this notice is happening. It feels unecessary and requires me to write a lot of extra lines of code sometimes. What is the reason for PHP having this strange restriction? Why does this problem even exist?
end() or array_pop() will return the E_NOTICE with message
Only variables should be passed by reference
The reason is that end() requires a reference, because it makes the current element pointer point to the last element.
You can do it with one line,
$string = "this-is-a-sample-text";
echo substr(strrchr($string, '-'), 1);
DEMO: https://3v4l.org/jO29n
Finally I found a great explanation which helped me to understand this: What's the difference between passing by reference vs. passing by value?
As Daniel Pryden states:
In simplest terms:
call by value means that you pass values as function arguments
call by reference means that you pass variables as function arguments
In metaphoric terms:
Call by value is where I write down something on a piece of paper and hand it to you. Maybe it's a URL, maybe it's a complete copy of
War and Peace. No matter what it is, it's on a piece of paper which
I've given to you, and so now it is effectively your piece of paper.
You are now free to scribble on that piece of paper, or use that piece
of paper to find something somewhere else and fiddle with it,
whatever.
Call by reference is when I give you my notebook which has something written down in it. You may scribble in my notebook (maybe I
want you to, maybe I don't), and afterwards I keep my notebook, with
whatever scribbles you've put there. Also, if what either you or I
wrote there is information about how to find something somewhere else,
either you or I can go there and fiddle with that information.
In this case the notice "Only variables should be passed by reference" is still unjustified as we are only interested in retrieving the last value of the array. However the function end() is defined like
mixed end ( array &$array )
The & sign which states passing by reference is there for a certain reason: end() is not just returning the last element of an array, it also changes its internal pointer to the end. Therefore the array is modified.
If we only would return the last element of an array without touching the array there would be no need to pass the array by reference and we would not get this notice. But end() is somehow the wrong function for that.
What if there is no justification for me getting this notice?
Note that also the function to be called might be defined wrong. In my case I hade a function defined like this:
/**
* Flatten an array by one level if only needing a certain key value from a sub array.
*
* Example: [["foo"=>"bar","foo"=>"cheese"]]
* Result: ["bar","cheese"]
*
* #param $array: The input array.
* #param $key: The key to flatupshift. Default is 0.
* #return $array: The result
*/
private function array_flatupshift(&$array, $key = 0) {
$a = [];
foreach ($array as $item) {
if (is_object($item)) {
array_push($a, $item->$key);
} else if (is_array($item)) {
array_push($a, $item[$key]);
}
}
return $a;
}
This is simply a wrong function definition. So if you also get notices like this: Check if the function you call is defined correctly. Passing by reference does not make sense here as the array being passed is not touched in any way. Therefore the function definition should be without the "reference &/":
private function array_flatupshift($array, $key = 0) {
There are some cases where you MIGHT use the error control operator if you know what you are doing. Therefore:
$string = "hi-dude";
echo #end(explode('-', $string));
... would be o.k. I guess is the result of explode is not needed anymore. However notice the drawbacks of suppressing all possible errors. Please correct me if I go wrong here.

PHP - get first value from array with single line using native functions

I have a function asdf() that returns an array ["key" => "value"]. I would like to print out value with one line, but reset() function suggested in similar questions does not work for me because reset only takes variable as a argument and doesent accept function. So if i try reset(asdf()) i get an exception: "Only variables should be passed by reference".
So my question is how can i print "value" from asdf() in a single line only using php native functions.
Actually reset function used to move the array's internal pointer to the first element, I think you must use current function that is return the current element in an array
Try like this
print current(asdf());
Try this:
current(array_values(asdf()));
It uses current to avoid the pass by reference error and array_values to ensure the array passed to current has the first element as it's current element.
Though unless you have a very good reason assigning the array to a variable and then using reset would be better.

Passing an array as a parameter in a custom function

Hey,
I was wondering if it was possible to pass an associative array as a parameter in a custom function. This is my scenario:
In the php file I set the array:
$dataArr = array('one'=>'1','two'=>'2','three'=>'3');
$tpl->assign('dataArr',$dataArr);
This is my custom function dulled down
function smarty_function_drawChart($params, &$smarty){
print_r($params);
}
This is my function call in the template
{drawChart data={$dataArr} title='Title of the Chart'}
The problem I am having is that if you notice where I print_r($params), that shows:
Array
(
[data] => Array
[title] => Title of the Chart
)
It seems to be passing the string 'Array' rather than the actual array. I have done debugging right before passing the $dataArr that shows {$dataArr.one} has a value. Once inside my custom function $params['data'].one does not exist.
Any ideas on what I am doing wrong?
Thanks
Levi
I am still not 100% sure why my code above didn't work. My thought is that the brackets work just as an 'echo' would do in php, which is why the string 'Array' was being passed into the function. I was able to get it to work by simple removing the brackets around the $dataArr variable.
This was my original call:
{drawChart data={$dataArr} title='Title of the Chart'}
This is my new call that works
{drawChart data=$dataArr title='Title of the Chart'}

Categories