We know we can't store a function in variable
<?php
$k = echo("hello");
?>
or
$k = unset($_SESSION['name']);
They all will give error. because we can't store a function in variable directly, but how we can use.
$row = mysqli_fetch_assoc($result);
I know mysqli_fetch_assoc() function output an array which is stored in variable $row . but how a general rule of php is violated. and we are able to store function in a variable
echo and unset are not really functions. If you check the documentation, you'll see that it says:
Return Values
No value is returned
Since no value is returned, you can't assign them to variables.
mysqli_fetch_assoc() is an ordinary function. And like any other function, you can assign its return value to a variable, or pass it as an argument to another function, or use it in an expression.
You would have a hard time programming in PHP if you couldn't assign function values to variables. You couldn't write things like:
$max = max($var1, $var2);
$current_time = time();
We know we can't store a function in a variable
This is not true, but I'll get back to it later.
You are misunderstanding the syntax below:
$variable = functionName();
This does not mean that the function is stored in a variable. It means that the value returned by the function is stored in the variable.
So there is nothing special about:
$row = mysqli_fetch_assoc($result);
You should also know as I hinted at in the beginning, that we can in fact store a function in a variable:
//store the function in variable $func
$func = function($a, $b){return $a + $b;}
//execute the function stored in variable $func
echo $func(2,8); //prints 10
These types of functions -- functions without names -- care called anonymous functions or closures. See the manual
Related
I have a method in a class with this signature:
public static function execute($query, $data = array(), &$result = NULL, $onlyOne = true)
The point is to execute a SQL query with data (if relevant) and modify the result variable (if set to true) and finally returning only first row if the caller is interested in it only. It handles SQL errors etc. and overall is a convenience thing as I try to reduce the sql queries in the script to single line or two (checking the result).
Now I have a problem with this:
Db::execute("query with :data", array(":data" => "data"), ($row = true));
The PHP complains about the $row not being a variable:
Strict standards: Only variables should be passed by reference
As I understand the PHP scopes the scope is function-wide and not block-wide (as in C++ for example). Therefore the $row should be a variable in my function scope and available for passing as reference (and not just a temporary inside the function call). If I declare it beforehand it works but it inflates the code somewhat. Is there a way to keep the declaration of that variable in the function call like this?
EDIT: To add to the accepted answer. The reference can be assigned any default value so I changed my signature to:
public static function execute($query, $data = array(), &$result = -1, $onlyOne = true)
which allows me to call it using:
Db::execute("query with :data", array(":data" => "data"), $row);
without pre-declaring the result variable. Inside I simply check if the $result is not -1 (or I could check if it is NULL signifying new empty variable) to fill the result in.
Db::execute("query with :data", array(":data" => "data"), ($row = true));
^^^^^^^^^^^^^
That's an assignment. In PHP, the result of an assignment is the value being assigned, so you're passing true in to your function. That argument is defined as a reference, and you can't create a reference to true.
You'd have to do:
$row = true;
DB::execute(....., $row);
I'm trying to extract values from an array, and pass them to a function where they'll be used. I've used echo inside the function for this example.
I'm using extract to get all the values.
Thing is, this wont work. Do you see how this can be done?
<?php
$my_array = array("a" => "Prince", "b" => "Funky"); // around 10 more
$g = extract($my_array);
foo($g);
function foo($g) {
echo 'My name is '.$a.', and I am '.$b;
}
?>
Functions in PHP have a different scope, so the variables $a, $b etc. aren't available inside your function. Trying to use them inside the function would result in Undefined variable notices (if you enable error reporting, that is).
Right now, you're storing the return value of extract() (which is the total number of variables parsed) into your function. You want the values instead, so change your function like so:
function foo($array) {
extract($array);
echo 'My name is '.$a.', and I am '.$b;
}
Note that I've moved the extract() call inside the function. This way, you wouldn't pollute the global scope with random variables (which may have undesired results and will make your debugging hard for no reason).
Now you can call your function, like so:
foo($my_array);
Output:
My name is Prince, and I am Funky
Demo
It's better to avoid extract() altogether, though. See: What is so wrong with extract()?
You can pass your array in your function as you do with any other variable
$my_array = array("a" => "Prince", "b" => "Funky"); // around 10 more
foo($my_array);
function foo($arrayData)
{
echo 'My name is '.$arrayData['a'].', and I am '.$arrayData['b'];
}
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'm 'dissecting' PunBB, and one of its functions checks the structure of BBCode tags and fix simple mistakes where possible:
function preparse_tags($text, &$errors, $is_signature = false)
What does the & in front of the $error variable mean?
It means pass the variable by reference, rather than passing the value of the variable. This means any changes to that parameter in the preparse_tags function remain when the program flow returns to the calling code.
function passByReference(&$test) {
$test = "Changed!";
}
function passByValue($test) {
$test = "a change here will not affect the original variable";
}
$test = 'Unchanged';
echo $test . PHP_EOL;
passByValue($test);
echo $test . PHP_EOL;
passByReference($test);
echo $test . PHP_EOL;
Output:
Unchanged
Unchanged
Changed!
It does pass by reference rather than pass by value.
This allows for the function to change variables outside of its own scope, in the scope of the calling function.
For instance:
function addOne( &$val ) {
$val++;
}
$a = 1;
addOne($a);
echo $a; // Will echo '2'.
In the case of the preparse_tags function, it allows the function to return the parsed tags, but allow the calling parent to get any errors without having to check the format/type of the returned value.
It accepts a reference to a variable as the parameter.
This means that any changes that the function makes to the parameter (eg, $errors = "Error!") will affect the variable passed by the calling function.
It means that the variable passed in the errors position will be modified by the called function. See this for a detailed look.
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.