Hello I'm writing an article allowing to bypass a filter that allows only base_convert except that there is something I discovered recently is that when we write this syntax in php:
"system"("id")
the function is interpreted, do you have a technical explanation for this?
Thanks to you !
Functions in PHP aren't first-class objects. What does that mean? When you want to pass around a function, for example as callback to array_map, you cannot just pass the function itself like so:
function my_callback() { ... }
array_map(my_callback, $some_array)
my_callback here is interpreted as a constant, and barring its existence, a bare string. (This works in other languages where functions are first class objects.) You can only pass the function by name, which means you pass a string that contains the name of the function:
array_map('my_callback', $some_array)
PHP will then look up the globally registered function with the name "my_callback" and use it.
This means inside array_map it must look something like this:
function array_map($callback, $array) {
$callback($array); // let's ignore the "mapping" part…
}
So, a variable can hold the name of a function, and "calling" that variable which holds the name of a function actually calls that function.
Now, we know that a variable can just as well be replaced with a literal of the same value:
$a = 1;
$b = 2;
$c = $a + $b;
is the same as:
$c = 1 + 2;
The same happens to hold for calling-strings-with-names-of-functions:
'my_callback'($array)
Note that this only works since PHP 7, where the PHP parser got a huge revamping. Before, $f() was sort of a special case hack, but the PHP 7+ parser properly follows the variable-is-substitutable-by-literal logic.
Related
Setup
I am borrowing a function from an open source CMS that I frequently use for a custom project.
It's purpose is not important to this question but if you want to know it's a simple static cache designed to reduce database queries. I can call getObject 10 times in one page load and not have to worry about hitting the database 10 times.
Code
A simplified version of the function looks like this:
function &staticStorage($name, $default_value = NULL)
{
static $data = array();
if (isset($data[$name])
{
return $data[$name];
}
$data[$name] = $default_value;
return $data[$name];
}
This function would be called in something like this:
function getObject($object_id)
{
$object = &staticStorage('object_' . $object_id);
if ($object)
{
return $object;
}
// This query isn't accurate but that's ok it's not important to the question.
$object = databaseQuery('SELECT * FROM Objects WHERE id = #object_id',
array('#object_id => $object_id'));
return $object;
}
The idea is that once I call static_storage the returned value will update the static storage as it is changed.
The problem
My interest is in the line $object = &staticStorage('object_' . $object_id); Notice the & in front of the function. The staticStorage function returns a reference already so I initially did not include the reference operator preceding the function call. However, without the reference preceding the function call it does not work correctly.
My understanding of pointers is if I return a pointer php will automatically cast the variable as a pointer $a = &$b will cause $a to point to the value of $b.
The question
Why? If the function returns a reference why do I have to use the reference operator to precede the function call?
From the PHP docs
Note: Unlike parameter passing, here you have to use & in both places - to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should be done for $myValue.
http://php.net/manual/en/language.references.return.php
Basically, its to help the php interpreter. The first use in the function definition is to return the reference, and the second is to bind by reference instead of value to the assignment.
By putting the & in the function declaration, the function will return a memory address of the return value. The assignment, when getting this memory address would interpret the value as an int unless explicitly told otherwise, this is why the second & is needed for the assignment operator.
EDIT: As pointed out by #ringø below, it does not return a memory address, but rather an object that will be treated like a copy (technically copy-on-write).
The PHP doc explains how to use, and why, functions that return references.
In your code, the getObject() function needs also a & (and the call as well) otherwise the reference is lost and the data, while usable, is based on PHP copy-on-write (returned data and source data point both to the same actual data until there is a change in one of them => two blocks of data having a distinct life)
This wouldn't work (syntax error)
$a = array(1, 2, 3);
return &$a;
this doesn't work as intended (no reference returned)
$a = array(1, 2, 3);
$ref = &$a;
return $ref;
and without adding the & to the function call as you said, no reference returned either.
To the question as to why... There doesn't seem to be a consistent answer.
if one of the & is missing PHP treats data as if it isn't a reference (like returning an array for instance) with no warning whatsoever
here some strangeness associated to functions returning references
PHP evolved during the years but still inherits some of the initial poor design choices. This seems to be one of them (this syntax is error prone as one may easily miss one &... and no warning ahead... ; also why not directly return a reference like return &$var;?). PHP made some progress but still, traces of poor design subsist.
You may also be interested in this chapter of the doc linked above
Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so.
Finally, it's better not to look too much for equivalences between the pointers in C and the PHP references (Perl is closer than PHP in this regard). PHP adds a layer between the actual pointer to data and variables and references point rather to that layer than the actual data. But a reference is not a pointer. If $a is an array and $b is a reference to $a, using either $a or $b to access the array is equivalent. There is no dereference syntax, a *$b for instance like in C. $b should be seen as an alias of $a. This is also the reason a function can only return a reference to a variable.
in many languages I can do something like this:
function f(a = 0, b = 0, c = 0)
{
// Do something
}
f(b=3, c=4);
Can I do something like this in PHP?
Thank you very much indeed!
No, unfortunately you can't "step over" arguments in PHP, so default values are only possible at the end of the list.
So you can write this:
function foo($a=0, $b=0) {}
foo(42);
Here $b will have its default value but $a won't, as we provided one value as input.
However there's no way of providing a value for $b without also providing one for $a - we have to provide the value for $b as the second parameter, and PHP has no keyword we can use in place of the first parameter to say "use default".
There is talk of adding named parameters to a future version of PHP, similar to your non-PHP example.
You can simulate this a bit with some changes to your code, though; a couple of ideas:
treat null as meaning "use default", and write $a = is_null($a) ? 42 : $a
make your functions take an associative array as their only parameter, and take values from it as though their keys were parameter names
Indeed.
function foo($bar = "test") {
echo "I want ".$bar;
}
In PHP this is not possible: see the PHP Manual. Function parameters are always evaluated from left to right.
However,
f($b=3, $c=4);
is possible, but does something different as you will expect: before the function f() is called, the arguments are evaluated (variable $b and $c get assigned with the values 3 and 4 resp.) and then the function is called as
f(3,4)
As side effect, the variables $b and $c are set to the new values.
I have function getArray(pram1, pram2) stored in database (MySQL) and it returns data in an array.
When I pass the query, it returns the function name as I stored it in the database,
but does not execute this function.
The code, which I'm using, is this:
$result=eval("return \$ret = $db_query_function;");
$db_query_function is variable that have function name getArray(pram1, pram2).
Error generated eval()'d code
You'll have to use call_user_func().
call_user_func('function_name', $parameter);
Firstly, it's probably not the best solution to store functions in the database.
If you want to store function implementations in the database, you'll have to store only the function body and parameter list separately, (but no name should be given to the function) so you can use create_function to put your function into a variable at runtime.
for example:
function add($a, $b)
{
return $a + $b;
}
should end up in variables similar to:
$arguments = '$a, $b'; // note single quotes, no variable expansion!
$implementation = 'return $a + $b;'; // single quotes again
$myFunction = create_function($arguments, $implementation);
now you can call your function:
$sum = $myFunction(10, 20); // $sum will now hold 30
If you just want your code stored in the database to be run, all you need is eval.
In both cases, you're most likely (but not definitely) missing a better/easier way to deal with yout code. In your sample, the most likely error is that pram1 and pram2 require a dollar sign in the string, but the code sample is incomplete enough to be sure. could also be that the function doesn't exist or you're missing a semicolon, or...
try:
$result = eval('return '.$db_query_function);
getArray(pram1, pram2).
Good luck.
I probably should have, but I've never seen this before. Ran into it when looking over the documenation of a Smarty Plugin.
$smarty =& new Smarty;
The =& sign in particular. If you enter it in Google, it gets ignored, just like any other search engine. What is this used for?
Same goes for this function signature:
function connect(&$smarty, $reset = false)
Why the & symbol?
Actually, this code is written to be compatible with PHP 4. The ampersand is useless in PHP 5 (as Tim said - since PHP 5, all objects are passed by reference).
With PHP 4, all variables were passed by value.
If you wanted to pass it by reference, you had to declare a reference assignment :
$ref_on_my_object =& new MyObject();
This code is still accepted with PHP 5 default configuration, but it's better to write :
$ref_on_my_object = new MyObject(); // Reference assignment is implicit
For your second problem, the issue is "almost" the same...
Because PHP lets you declare function arguments (resp. types), and you can't do it for return values.
An accepted, but "not so good" practice is to avoid reference declaration within the function's declaration :
function foo($my_arg) {
// Some processing
}
and to call with a reference...
$my_var;
$result = foo( &$my_var );
// $my_var may have changed because you sent the reference to the function
The ideal declaration would be more like :
function foo( & $my_input_arg ) {
// Some processing
}
then, the call looses the ampersand :
$my_var;
$result = foo( $my_var );
// $my_var may have changed because you sent the reference to the function
It is used for passing values by reference rather than by value which is default in php.
& passes an argument by reference. In this fashion, connect() can manipulate the $smarty object so that the calling function can retrieve the modified object.
Similarly, =& sets a variable by reference.
As Tim said its a reference to a variable. But if you're using a recent version of PHP then all class object are passed by reference anyway. You would still need this if you were passing about arrays, or other builtin types though.
The first example is returning reference, the second is passing reference.
You can read all about it in the PHP manual
& is PHP's reference operator. It's used to return a reference to the object. In this case "new Smarty".
The ampersand will assign a reference to the variable, rather than the value of the object.
One of the primary uses of the ampersand operator is to pass by memory address. This is usually something you do when you want to have a variable changed, but not be returned.
function test_array(&$arr)
{
$varr[] = "test2";
}
$var = array('test');
test_array($var);
print_r($var);
this should output
array( test , test2 );
The purpose of this is usually when you need to pass the actual copy[memory address] you are working with into another function / object. Typically it was used in the past to alleviate a lack of memory and speed up performance, it's a feature from C / C++ and a few other low level languages.
What does this code mean? Is this how you declare a pointer in php?
$this->entryId = $entryId;
Variable names in PHP start with $ so $entryId is the name of a variable.
$this is a special variable in Object Oriented programming in PHP, which is reference to current object.
-> is used to access an object member (like properties or methods) in PHP, like the syntax in C++.
so your code means this:
Place the value of variable $entryId into the entryId field (or property) of this object.
The & operator in PHP, means pass reference. Here is a example:
$b=2;
$a=$b;
$a=3;
print $a;
print $b;
// output is 32
$b=2;
$a=&$b; // note the & operator
$a=3;
print $a;
print $b;
// output is 33
In the above code, because we used & operator, a reference to where $b is pointing is stored in $a. So $a is actually a reference to $b.
In PHP, arguments are passed by value by default (inspired by C). So when calling a function, when you pass in your values, they are copied by value not by reference. This is the default IN MOST SITUATIONS. However there is a way to have pass by reference behaviour, when defining a function. Example:
function plus_by_reference( &$param ) {
// what ever you do, will affect the actual parameter outside the function
$param++;
}
$a=2;
plus_by_reference( $a );
echo $a;
// output is 3
There are many built-in functions that behave like this. Like the sort() function that sorts an array will affect directly on the array and will not return another sorted array.
There is something interesting to note though. Because pass-by-value mode could result in more memory usage, and PHP is an interpreted language (so programs written in PHP are not as fast as compiled programs), to make the code run faster and minimize memory usage, there are some tweaks in the PHP interpreter. One is lazy-copy (I'm not sure about the name). Which means this:
When you are coping a variable into another, PHP will copy a reference to the first variable into the second variable. So your new variable, is actually a reference to the first one until now. The value is not copied yet. But if you try to change any of these variables, PHP will make a copy of the value, and then changes the variable. This way you will have the opportunity to save memory and time, IF YOU DO NOT CHANGE THE VALUE.
So:
$b=3;
$a=$b;
// $a points to $b, equals to $a=&$b
$b=4;
// now PHP will copy 3 into $a, and places 4 into $b
After all this, if you want to place the value of $entryId into 'entryId' property of your object, the above code will do this, and will not copy the value of entryId, until you change any of them, results in less memory usage. If you actually want them both to point to the same value, then use this:
$this->entryId=&$entryId;
No, As others said, "There is no Pointer in PHP." and I add, there is nothing RAM_related in PHP.
And also all answers are clear. But there were points being left out that I could not resist!
There are number of things that acts similar to pointers
eval construct (my favorite and also dangerous)
$GLOBALS variable
Extra '$' sign Before Variables (Like prathk mentioned)
References
First one
At first I have to say that PHP is really powerful language, knowing there is a construct named "eval", so you can create your PHP code while running it! (really cool!)
although there is the danger of PHP_Injection which is far more destructive that SQL_Injection. Beware!
example:
Code:
$a='echo "Hello World.";';
eval ($a);
Output
Hello World.
So instead of using a pointer to act like another Variable, You Can Make A Variable From Scratch!
Second one
$GLOBAL variable is pretty useful, You can access all variables by using its keys.
example:
Code:
$three="Hello";$variable=" Amazing ";$names="World";
$arr = Array("three","variable","names");
foreach($arr as $VariableName)
echo $GLOBALS[$VariableName];
Output
Hello Amazing World
Note: Other superglobals can do the same trick in smaller scales.
Third one
You can add as much as '$'s you want before a variable, If you know what you're doing.
example:
Code:
$a="b";
$b="c";
$c="d";
$d="e";
$e="f";
echo $a."-";
echo $$a."-"; //Same as $b
echo $$$a."-"; //Same as $$b or $c
echo $$$$a."-"; //Same as $$$b or $$c or $d
echo $$$$$a; //Same as $$$$b or $$$c or $$d or $e
Output
b-c-d-e-f
Last one
Reference are so close to pointers, but you may want to check this link for more clarification.
example 1:
Code:
$a="Hello";
$b=&$a;
$b="yello";
echo $a;
Output
yello
example 2:
Code:
function junk(&$tion)
{$GLOBALS['a'] = &$tion;}
$a="-Hello World<br>";
$b="-To You As Well";
echo $a;
junk($b);
echo $a;
Output
-Hello World
-To You As Well
Hope It Helps.
That syntax is a way of accessing a class member. PHP does not have pointers, but it does have references.
The syntax that you're quoting is basically the same as accessing a member from a pointer to a class in C++ (whereas dot notation is used when it isn't a pointer.)
To answer the second part of your question - there are no pointers in PHP.
When working with objects, you generally pass by reference rather than by value - so in some ways this operates like a pointer, but is generally completely transparent.
This does depend on the version of PHP you are using.
You can simulate pointers to instantiated objects to some degree:
class pointer {
var $child;
function pointer(&$child) {
$this->child = $child;
}
public function __call($name, $arguments) {
return call_user_func_array(
array($this->child, $name), $arguments);
}
}
Use like this:
$a = new ClassA();
$p = new pointer($a);
If you pass $p around, it will behave like a C++ pointer regarding method calls (you can't touch object variables directly, but that's evil anyways :) ).
entryId is an instance property of the current class ($this)
And $entryId is a local variable
Yes there is something similar to pointers in PHP but may not match with what exactly happens in c or c++.
Following is one of the example.
$a = "test";
$b = "a";
echo $a;
echo $b;
echo $$b;
//output
test
a
test
This illustrates similar concept of pointers in PHP.
PHP passes Arrays and Objects by reference (pointers). If you want to pass a normal variable Ex. $var = 'boo'; then use $boo = &$var;.
PHP can use something like pointers:
$y=array(&$x);
Now $y acts like a pointer to $x and $y[0] dereferences a pointer.
The value array(&$x) is just a value, so it can be passed to functions, stored in other arrays, copied to other variables, etc. You can even create a pointer to this pointer variable. (Serializing it will break the pointer, however.)