What do braces surrounding a member variable mean in PHP? - php

I am wondering what { } in the following. What { } is doing here? $this->{$key} = $value;
Thanks in advance.
In one file
$config['field']['calendar'] = array('type'=>'boolean');
$config['field']['category'] = array('type'=>'boolean');
$config['field']['customers'] = array('type'=>'boolean');
...
$this->preference_form->initalize($config);
And in Preference_form.php
function initalize($config = array())
{
foreach($config as $key => $value)
{
$this->{$key} = $value;
}
}

They're optional in this case, but it's a way of making it clearer to the reader (and the parser) that you're referring to a variable.
http://www.php.net/manual/en/language.variables.variable.php
In order to use variable variables with arrays, you have to resolve an
ambiguity problem. That is, if you write $$a[1] then the parser needs
to know if you meant to use $a[1] as a variable, or if you wanted $$a
as the variable and then the [1] index from that variable. The syntax
for resolving this ambiguity is: ${$a[1]} for the first case and
${$a}[1] for the second.
Another case where this syntax is useful is when expanding a function call in a string.
This doesn't work (or rather it'll evaluate $someObj as a string, and then append ->someFunc():
$myString = "$someObj->someFunc()";
But this does what you'd expect:
$myString = "{$someObj->someFunc()}";

It's escaping the variable expression so that the member can be set dynamically.
Take a look at the documentation here: http://php.net/manual/en/language.types.string.php#language.types.string.parsing.complex

Related

PHP variable variable name containing index

$arr[0]=123;
$a="arr[0]";
echo $$a;
gives me error
Notice: Undefined variable: arr[0]
on the last line.
What should I do to make it work?
EDIT:
Above is the simplification of what I want to do. If someone wants to know why I want to do this, then here's the explanation:
This is something like what I want to do:
if(condition){
$a=$arr1[0][0];
$b=$arr1[0][1];
$c=$arr1[0][2];
}
else{
$a=$arr2[0];
$b=$arr2[1];
$c=$arr2[2];
}
I can compact it like this:
if(condition)
$arr=$arr1[0];
else
$arr=$arr2;
$a=$arr[0];
$a=$arr[1];
$a=$arr[2];
But I wanted to try doing this using variable variable:
if(condition)
$arr="$arr1[0]";
else
$arr="$arr2";
$a={$$arr}[0];
$b={$$arr}[1];
$c={$$arr}[2];
Sure, we don't need variable variables as we can still code without them. I want to know, for learning PHP, why the code won't work.
Now that you said what you’re actually trying to accomplish: Your code doesn’t work because if you look at $arr1[0][0], only arr is the variable name; the [0] are special accessors for certain types like strings or arrays.
With variable variables you can only specify the name but not any accessor or other operation:
A variable variable takes the value of a variable and treats that as the name of a variable.
Your solution with the additional variable holding the array to access later on would be the best solution to your problem.
What you are trying to do just won't work - the code $arr[0] is referencing a variable called $arr, and then applying the array-access operator ([$key]) to get the element with key 0. There is no variable called $arr[0], so you cannot reference it with variable-variables any more than you could the expression $foo + 1 .
The real question is why you want to do this; variable variables are generally a sign of very messy code, and probably some poor choices of data structure. For instance, if you need to select one of a set of variables based on some input, you probably want a hash, and to look up an item using $hash[$item] or similar. If you need something more complex, a switch statement can often cover the cases you actually need.
If for some reason you really need to allow an arbitrary expression like $arr[0] as input and evaluate it at runtime, you could use eval(), but be very very careful of where the input is coming from, as this can be a very easy way of introducing security holes into your code.
FROM PHP DOC
In order to use variable variables with arrays, you have to resolve an ambiguity problem. That is, if you write $$a[1] then the parser needs to know if you meant to use $a[1] as a variable, or if you wanted $$a as the variable and then the [1] index from that variable. The syntax for resolving this ambiguity is: ${$a[1]} for the first case and ${$a}[1] for the second.
Use
echo ${$a}[0]; // 123
Edit : Based on your edit you can simply have
list($a, $b, $c) = (condition) ? $arr1[0] : $arr2;
Or
$array = (condition) ? $arr1[0] : $arr2;
$a = $array[0];
$b = $array[1];
$c = $array[2];
As pointed out you don't need variable variables. To get a PHP variable variable name containing index (a key) use array_keys() or array_search() or other array parsers. From php's site:
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
You could also use the following (using $var= instead of echo):
$arr[0]=123;
$arr[1]=456;
foreach ($arr as $key => $value) {
echo "arr[{$key}] = {$value} \r\n";
}
Which outputs:
arr[0] = 123
arr[1] = 456
But I don't see why you'd do that, since the whole point of the array is not doing that kind of stuff.

PHP. Pass variable by reference vs string. How to works with these two different arguments?

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.

PHP get array() value to become $variable

ok, So I have this array:
$choices = array($_POST['choices']);
and this outputs, when using var_dump():
array(1) { [0]=> string(5) "apple,pear,banana" }
What I need is the value of those to become variables as well as adding in value as the string.
so, I need the output to be:
$apple = "apple";
$pear = "pear";
$banana = "banana";
The value of the array could change so the variables have to be created depending on what is in that array.
I would appreciate all help. Cheers
Mark
How about
$choices = explode(',', $_POST['choices']);
foreach ($choices as $choice){
$$choice = $choice;
}
$str = "apple,pear,pineapple";
$strArr = explode(',' , $str);
foreach ($strArr as $val) {
$$val = $val;
}
var_dump($apple);
This would satisfy your requirement. However, here comes the problem, since you could not predefine how many variables are there and what are they, it's hard for you to use them correctly. Test "isset($VAR)" before using $VAR seems to be the only safe way.
You'd better just split the source string in just one array and just operate the elements of the specific array.
I have to concur with all the other answers that this is a very bad idea, but each of the existing answers uses a somewhat roundabout method to achieve it.
PHP provides a function, extract, to extract variables from an array into the current scope. You can use that in this case like so (using explode and array_combine to turn your input into an associative array first):
$choices = $_POST['choices'] ?: ""; // The ?: "" makes this safe even if there's no input
$choiceArr = explode(',', $choices); // Break the string down to a simple array
$choiceAssoc = array_combine($choiceArr, $choiceArr); // Then convert that to an associative array, with the keys being the same as the values
extract($choiceAssoc, EXTR_SKIP); // Extract the variables to the current scope - using EXTR_SKIP tells the function *not* to overwrite any variables that already exist, as a security measure
echo $banana; // You now have direct access to those variables
For more information on why this is a bad approach to take, see the discussion on the now deprecated register_globals setting. In short though, it makes it much, much easier to write insecure code.
Often called "split" in other langauges, in PHP, you'd want to use explode.
EDIT: ACTUALLY, what you want to do sounds... dangerous. It's possible (and was an old "feature" of PHP) but it's strongly discourage. I'd suggest just exploding them and making their values the keys of an associative array instead:
$choices_assoc = explode(',', $_POST['choices']);
foreach ($choices as $choice) {
$choices_assoc[$choice] = $choice;
}

How to get variable name in PHP?

func($name1) should return name1
Is it possible?
Here's a function that does it.
function var_name (&$iVar, &$aDefinedVars)
{
foreach ($aDefinedVars as $k=>$v)
$aDefinedVars_0[$k] = $v;
$iVarSave = $iVar;
$iVar =!$iVar;
$aDiffKeys = array_keys (array_diff_assoc ($aDefinedVars_0, $aDefinedVars));
$iVar = $iVarSave;
return $aDiffKeys[0];
}
Call it like this
$test = "blah";
echo var_name($test, get_defined_vars());
That will print out "test".
I originally found that function over here You can also do it by iterating over the array returned by get_defined_vars(). That might be a bit easier to understand.
No, there is no way to get the name of a variable in PHP.
When calling a function, that function will only receive the content of the variable, and not the "variable itself" -- which means a function cannot find out the name of the variable that was passed to it.
Good Idea ? No
Any usecase you where you should do it ? No
Proof of concept ? Sure !
<?php
a($test);
function a($x) {
$trace = debug_backtrace();
$file = file($trace[0]['file']);
$line = $file[$trace[0]['line']-1];
var_dump($line); // Prints "a($test);" Do the Stringparsing and your done
}
Yes, this takes the "easy" by reading the sourcefile, it is also doable by using a php extension called "bytekit" that gives you userland access to the php opcodes and work from there.
No.
When you define a function, you specify a local variable name for it to have inside the scope of that function. PHP will pass the function the appropriate value, but the symbol is no longer in scope.
You could look into using "variable variables" as an alternative, however.
Obviously, it is possible for sufficiently high values of crazy.
The comments on this page include several techniques:
http://php.net/manual/en/language.variables.php
lucas dot karisny at linuxmail dot org's answer works on my machine:
http://www.php.net/manual/en/language.variables.php#49997
YMMV.

Find the name of a calling var

Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"

Categories