What does this line mean?
if ( ${fun("str1")} (fun("str2"), ${fun("str3")}) )
Evaluate function returning_value_for_str1_of_fun()_name with the parameters return value for str2 and variable with name return_value_for_str3 ?
This tests the return value of the function, whose name is the value in the variable named fun("str1"), and given the arguments fun("str2") and the value of the variable named fun("str3").
Example:
If fun("str1") equals "x", fun("str2") equals 34, and fun("str3") equals "y", then the statement would look like:
if ( $x (34, $y) )
fun("str1") returns string that should be name of variable and the value of this variable is anonymous function (that probably is not void and returns boolean) that gets two arguments first is return value fun("str2") and the second is the value of the variable with the name that matches string returned by fun("str3").
Wow. That's convoluted code. Let's examine it bit by bit:
Let's start with this:
fun("str1")
In fact, this is simply a function call to a function named fun(), passing in a string value as a parameter.
This function call is repeated three times in your code, with different strings as the arguments. The function fun() itself is not supplied in your example code, so I can't tell what it does, but given the context I assume it returns a string.
Which leads us onto the next bit we can examine:
${fun("str1")}
The ${...} syntax in PHP takes the contents of the braces and references a variable of that name.
So, for example, ${"myvar"} is the same as saying $myvar. This is called a dynamic variable name. While it does have its uses, it is a very easy way to write bad code, that is difficult to read, understand or maintain. Your example definitely falls into this category.
However, now that we understand the syntax, it's easy to see that it is taking the string output of the fun() function call, and turning it into a variable name.
Expanding further, we can rewrite the code as follows to make it clearer:
$var1 = fun("str1");
$var2 = fun("str2");
$var3 = fun("str3");
if ( $$var1 ($var2, $$var3) )
Here, $$var1 is being used as a function name, called with $var2 and $$var3 as parameters.
So in $var1, we have a function call returning a string that is being referenced as a variable name, which is being called as a function.
We still don't know what fun() function returns, or whether the variable names that are generated by its return are valid, but we can make some assumptions, as $var1 and $var2 would need to be populated with valid function names in order for your line of code to work at all.
We now have an understanding of the whole line of code, but still not a clear view of what it's trying to acheive (beyond being excessively 'clever' and obtuse).
This is very very poorly written code. It is deliberately obscure, and inefficient (ie it will run slowly).
Some work around:
$func = 'fun';
$str3 = 'str3';
echo ${fun("str1")} (fun("str2"), ${fun("str3")}); // will output 'str2'
function fun($param1, $param2 = ''){
if($param1 == 'str2' || $param1 == 'str3')
return $param1;
elseif($param1 == 'str1')
return 'func';
else
echo ' you are done';
}
Evaluates as follows:
fun("str1") -> 'func'
${fun("str1")} -> $func -> fun
fun("str2") -> 'str2'
fun("str3") -> 'str3'
${fun("str3")} -> $str3
${fun("str1")} (fun("str2"), ${fun("str3")})
=> $func ("str2", $str3)
=> fun("str2", "str3")
=> "str2"
Related
First, let me start by saying i'm a real beginner learning mostly PHP. Understanding the patterns and semantics of programming is more important to me than just learning the syntax. I did some research for what I'm going to ask, but I couldn't find any info about it. So, I was thinking... What if I need to do the following... Give a function multiple outputs to pass in other parts of the code. What is the name of this type of functionality (if it exists)? Or If it doesn't exist, why not? And what is the best practice to achieve the same semantic?
More details:
Let's say I want to call a function with one argument and return not only the value back to that same argument call location, but also in another location or into some other part of the program. Meaning a function with two outputs in two different locations, but the second location wouldn't be a call, just an output from the call made in the first location, returned at the same time with the same value output as the first. So, not calling it twice separately... But rather calling once and outputting twice in different locations. The second output would be used to pass the result into another part of the program and therefore wouldn't be appropriate as a "call/input", but more as an "output" only from the "input" value. How can I achieve multiple outputs in functions?
If this seems like a stupid question, I'm sorry. I couldn't find the info anywhere. Thanks in advance
What you want to do is basically this (i'll make it a 'practical' example):
function add($number1, $number2)
{
$result = $number1 + $number2;
return array('number1' => $number1,'number2' => $number2,'result' => $result);
}
$add = add(5,6); // Returns array('number1' => 5, 'number2' => 6, 'result' => 11);
You now have the two arguments and the result of that function at your disposal to use in other functions.
some_function1($add['result']);
...
some_function2($add['number1']);
If the question is about returning more than one variables, it is simply:
function wtf($foobar = true) {
$var1 = "first";
$var2 = "second";
if($foobar === true) {
return $var2;
}
return $var1;
}
You can either have the function return an array of values:
function foo($bar) {
$bat = 1;
return [$bar, $bat];
}
Or you can pass an argument that tells it which value to return:
function foo($bar, $return_bar=false) {
$bat = 1;
return $return_bar ? $bar : $bat;
}
I inherited a php codebase that contains some variable assignments in function calls:
<?php
function some_func($foo, $state) {
....
}
some_func("random stuff", $state = true);
...
some_func("other stuff", $state = false);
...
?>
I did some research and some tests, but I can't find out what the defined behaviour for this code is in PHP.
How is the value of the second argument to some_func() computed? The content of the 4state variable (true on first call, false on second)? Or is it the outcome of the assignment (i.e. assigning true/false to the variable $state was successful, so some_func received true?
What is the value of the $state variable in the global scope? The result of the assignment, i.e. true after the first call, false after the second?
I too had to work with a codebase that had function calls similar to this. Luckily, I had access to developers that wrote the code. Here is what I learned.
Scenario 1:
Simply a way to document the code. You know the variable name that you are passing into the function.
Scenario 2:
Here is a link: http://www.php.net/manual/en/language.references.pass.php
If you see, they do specifically call out your case:
foo($a = 5); // Expression, not variable
A 'dummy' pass-by-ref. Depending on your version of PHP, it may throw a warning. I was getting this: Strict Standards: Only variables should be passed by reference in ...
Now let me go into detail of what is happening in this situation.
The dangerous thing is that your example that you have provided wont display the "gotcha!" behavior. In a case like this, your $arg2 that you are echoing outside of the function will always be what the expression in the function call set it to be. Furthermore, the function that is being called will also be sent a "copy" of that value, and work with that. I say "copy" because even though the function is requiring a pass-by-ref, it is actually getting a copy, similar to what a normal function parameter would get.
If you modify the $arg2 that is inside of the function it WILL NOT modify the $arg2 that is outside of the function, as you would expect from a function that is pass-by-ref.
To assign a variable at function call time, you have to pass it as a reference (&$var):
function my_function($arg1, &$arg2) {
if ($arg1 == true) {
$arg2 = true;
}
}
my_function(true, $arg2 = false);
echo $arg2;
outputs 1 (true)
my_function(false, $arg2 = false);
echo $arg2;
outputs 0 (false)
How is the value of the second argument to some_func() computed?
It's not "computed" but explicitly setup : $state = true / false and then passed as argument to some_func().
What is the value of the $state variable in the global scope?
$state does not exist in the global scope.
I'm writing my own debug functions and I need some help to fix the code below.
I'm trying to print a variable and its name, the file where the variable and the function was declared and the line of the function call. The first part I did, the variable, the variable name, the file and the line is printed correctly.
At the code, a($variable) works good.
The problem is I'd like this function accepts a string too, out of a variable. But PHP returns with a fatal error (PHP Fatal error: Only variables can be passed by reference in ...). At the code, a('text out').
So, how can I fix this code to accept a variable or a string correctly?
code (edited):
function a(&$var){
$backtrace = debug_backtrace();
$call = array_shift($backtrace);
$line = $call['line'];
$file = $call['file'];
echo name($var)."<br>".$var."<br>".$line."<br>".$file;
}
$variable='text in';
a($variable);
a('text out');
I need pass the variable by reference to use this function below (the function get the variable name correctly, works with arrays too):
function name(&$var, $scope=false, $prefix='unique', $suffix='value'){
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = $prefix.rand().$suffix;
$vname = FALSE;
foreach($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
The way your code is currently implementing pass by reference is perfect by design, but also by design cannot be changed to have two a() methods - one accepting a variable by reference and the other as a string-literal.
If the desire to pass a string literal instead of assigning it to a variable first is really needed, I would suggest creating a second convenience method named a_str() that actually accepts a string-literal instead of a variable by reference. This method's sole-purpose would be to relay the variable(s) to the original a() method - thereby declaring a variable to pass by reference.
function a_str($var) {
a($var);
}
The only thing to remember is, use a($variable); when passing by reference and a_str('some text'); when not.
Here is the same convenience-method for your name() function:
function name_str($var, $scope=false, $prefix='unique', $suffix='value'){
return name($var, $scope, $prefix, $suffix);
}
The only way to do what you are asking without writing an additional function like #newfurniturey suggests is plain and simply opening and parsing the file where your function was called as text (e.g. with fopen), using the data from debug_backtrace. This will be expensive in terms of performance, but it might be ok if used only for debugging purposes; and using this method you will no longer need a reference in your function, which means you can freely accept a literal as the parameter.
I understand I can define a function like this:
<?php
function say_hello() {
echo "hello world!";
}
say_hello();
?>
...and then reuse this function elsewhere as many times as I need by just calling the function by name.
What I don't understand is "passing data to arguments within the function". I'm confused what's meant by within.
From one of the lessons I've been studying, I have this function:
<?php
function say_helloTWO( $word ) {
echo " {$word} hello world a second time ";
}
say_helloTWO( "my name is mike");
?>
This prints on screen
my name is mike hello world a second time
When I test the function with the argument "my name is mike", it prints to screen, but I don't understand how this works. The variable $word wasn't declared anywhere, so, if I take out the "$word" from the echo, then only "hello world a second time" shows without the my name is mike.
This leads me to believe that somewhere within this block of code, $word was defined, is that right?
In your second function $word is being declared in the function definition function say_helloTWO( $word ).
So the function is expecting 1 parameter, which will be assigned to the variable $word for use within that function.
So when you call say_helloTWO( "my name is mike"); you are passing 1 parameter ("my name is mike") to the function say_helloTWO. This 1 parameter gets assigned to the 1st variable in the function definition, and is therefore available within the function as $word.
Make sense?
In this case the function definition is said to take one arguments.
function say_helloTWO( $word ) // $word is the name of this argument
When you call the function in your code the first thing you pass in the brackets will be passed as the first argument. Therefore in your example the string "my name is mike" is being passed into the function and assigned to the variable $word.
If we expand on this and have a function that takes two arguments like this
function say_helloTHREE( $word, $secondArg )
Then this function would now expect two arguments to be passed into it. The first argument would be assigned to $word and the second argument will be assigned to $secondArg.
You need to read this: http://php.net/manual/en/functions.arguments.php
<?php
function say_helloTWO( $word ) {
echo " {$word} hello world a second time ";
}
say_helloTWO( "my name is mike");
?>
In this code, the 'declaration' of the variable $word is made within the function declaration. As you see on this line function say_helloTWO( $word ) { you can find $word on that line. This is enough for the PHP parser to know that for the first agument of the is to be known as word within this functions scope. The function then echos out that variable on a later line echo " {$word} hello world a second time "; where again $word is present prints out both what you set as the value of the first argument on this line say_helloTWO( "my name is mike");.
Good question.
This counts as a valid declaration. It's defined when supplied as an argument when the function is called.
<?php
function my_name_is ($name) {
echo "Hello, my name is " . $name;
}
my_name_is('mike');
// returns 'Hello, my name is mike'
?>
Because, when calling the function, they supply 'mike' as an argument, $name becomes 'mike'. It's just how functions work.
EDIT:
It's a special rule. $name doesn't need to be declared because it will be defined when the function is called. PHP understands this. If you don't supply an argument, it's still defined, it's just empty... I believe.
It's passed as a parameter. So it was sorta already declared inside the parenthesis
If you did:
function say_helloTWO( $word1, $word2, $word3 )
and called:
say_helloTWO("a", "b", "c");
That would call say_helloTWO and set the variable $word1 to "a", $word2 to "b" and $word3 to "c"
Those three variables are defined in say_helloTWO for the duration that that function is running.
To give a practical example, say you had a function to solve quadratic equations, it would look like
function quadratic( $a, $b, $c ) {
$x = ( $b + sqrt( (b*b - 4*a*c) ) )/ 2*a;
return $x;
}
Then, instead of rewriting the code to solve a quadratic each time, you could call it like this:
$y = quadratic (1, 2, 3);
This would set $a to 1, $b to 2 and $c to 3, and store the result in $y.
You can consider the quadratic function to be a sort of "mini-program", independent of the rest of your program, $a, $b and $c only apply within the quadratic function.
this leads me to believe that somewhere within this block of code, $word was defined, is that right?
No, $word is not defined within the function block, it is given the value of "my name is mike" when you mane the call.
In other words, $word is defined when you call the function:
/* here you are defining word to "my name is mike" */
say_helloTWO( "my name is mike");
/* here you are defining word to "my name is jack"*/
say_helloTWO( "my name is jack");
If the above still don't make much sense to you then I think you may need to go back to the basic and study what is a function in programming world.
I'm building a small abstract class that's supposed to make certain tasks easier.
For example:
$var = class::get('id');
would run check if there's pointer id in the $_GET, returning a string or array according to parameters. This should also work for post and request and maby more.
I'm doing it in the way there's function for all the superglobals. I'm using get as example:
get function gets a pointer as parameter, it calls fetchdata function and uses the pointer and "$_GET" as the parameters.
fetchdata is supposed to just blindly use the string it got as superglobal and point to it with the other param. Then check if it exists there and return either the value or false to get function, that returns the value/false to caller.
Only problem is to get the string work as superglobal when you don't know what it is. I did this before with a switch that checked the param and in case it was "get", it set $_GET to value of another variable. However I don't want to do it like that, I want it to be easy to add more functions without having to touch the fetchdata.
I tried $method = eval($method), but it didn't work. ($method = "$_GET"), any suggestions?
EDIT: Sorry if I didn't put it clear enough. I have a variable X with string value "$_GET", how can I make it so X gets values from the source described in the string?
So simply it's
$X = $_GET if X has value "$_GET"
$X = $_POST if X has value "$_POST"
I just don't know what value X has, but it needs to get data from superglobal with the same name than its value.
According to this page in the manual:
Note: Variable variables
Superglobals cannot be used as variable variables inside functions or class methods.
This means you can't do this inside a function or method (which you would be able to do with other variables) :
$var = '_GET';
${$var}[$key]
Instead of passing a string to fetchdata(), could you not pass $_GET itself? I think PHP will not copy a variable unless you modify it ('copy on write'), so this shouldn't use memory unnecessarily.
Otherwise there are only nine superglobals, so a switch-case as you have suggested isn't unreasonable.
You could do this with eval() if you really had to, something like:
eval('return $_GET;');
I think that would be unnecessary and a bad idea though; it is slow and you need to be extremely careful about letting untrusted strings anywhere near it.
Don't use eval. Just use reference.
//test value for cli
$_GET['test'] = 'test';
/**
* #link http://php.net/manual/en/filter.constants.php reuse the filter constants
*/
function superglobalValue($key, $input = null) {
if ($input === INPUT_POST)
$X = &$_POST;
else
$X = &$_GET;
return (isset($X[$key]) ? $X[$key] : false);
}
function getArrayValue(&$array, $key) {
return (array_key_exists($key, $array) ? $array[$key] : false);
}
//test dump
var_dump(
superglobalValue('test', INPUT_GET),
superglobalValue('test', INPUT_POST),
getArrayValue($_GET, 'test'),
getArrayValue($_POST, 'test')
);
$_GET, $_POST and $_REQUEST dont have any null values by default, only string or array. So I used isset there instead of array_key_exists.
Param order: I always put required params before optional when I can, and the data objects before the manipulation/subjective params. Thats why key is first param for superglobalValue and second param for getArrayValue.
I'm not quite sure what you're trying to achieve, but you could have a look at the __callStatic magic method
class example{
protected static $supers = array('GET', 'POST', 'SERVER', 'COOKIE');
public static function __callStatic($functionName, $arguments){
$index = arguments[0];
$desiredSuper = strtoupper($functionName);
if(in_array($desiredSuper, self::$supers)){
doStuff ( $_{$desiredSuper}[$index] );
}
else{
throw new Exception("$desiredSupper is not an allowed superGlobal");
}
}
}
you could then do:
example::get('id'); //wo do stuff to $_GET['id']
example::server('REQUEST_METHOD'); //Will do stuff to $_SERVER['REQUEST_METHOD']
example::foo('bar'); //throws Exception: 'FOO is not an allowed superGlobal'
Php manual on magic methods: http://ca.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
Edit
I just noticed your edit, you could try:
$X = {$X};
You can use $_REQUEST["var"] instead of $_GET["var"] or $_POST["var"].
A more complicated way would be to test if the variable exists in the GET array, if it doesnt then its POST. If it does its GET.
$var = null;
if (isset($_GET["varname"]))
{
$var = $_GET["varname"];
}
else
{
$var = $_POST["varname"];
}
If you want a variable to be accessible globally, you can add it tot he $GLOBALS array.
$GLOBALS['test']='test';
Now you can fetch $GLOBALS['test'] anywhere.