$a = some object;
$b = another object;
function do_some_stuff() {
$c = $a;
$b->a_property = $c;
}
do_some_stuff();
echo $b->a_property; # Undefined, becuase $c was deleted when the function exited.
When I type $b->a_property = $c, I want the PHP interpereter to do $b->a_property = $a. How do I do that, if I'm unable to assign it to $a directly?
My actual code is:
function setup() {
$playerHeroes = [];
$enemyHeroes = [];
foreach ($entities as $object) {
if ($object->team == "player") {
$playerHeroes[] = $object;
}
else if ($object->team == "enemy") {
$enemyHeroes[] = $object;
}
}
foreach ($playerHeroes as $object) {
$object->target = $enemyHeroes[array_rand($enemyHeroes)];
}
foreach ($enemyHeroes as $object) {
$object->target = $playerHeroes[array_rand($playerHeroes)];
}
}
I sort through a list of entities in the game as either being on the player's team or being on the enemy's team. Each hero must target a hero on the opposing team. When the setup function exits, $object, $playerHeroes and $enemyHeroes get destroyed. The ->target properties are accessed later, and it's null. How do I make it so that when I assign a variable to a reference of an object, it assigns it to the object itself?
EDIT: I want the variable to change when the object changes, so cloning/copying by value is not an option.
In addition to echoing the comments from #IvoP and #mega6382, it's worth noting that the problem you're having is not a "solvable" one per se. That's because what you're running into is fundamental to how objects work in PHP. You can learn all about it at http://ca2.php.net/manual/en/language.oop5.references.php.
One of the key-points of PHP 5 OOP that is often mentioned is that "objects are passed by references by default". This is not completely true. This section rectifies that general thought using some examples.
A PHP reference is an alias, which allows two different variables to
write to the same value. As of PHP 5, an object variable doesn't
contain the object itself as value anymore. It only contains an object
identifier which allows object accessors to find the actual object.
When an object is sent by argument, returned or assigned to another
variable, the different variables are not aliases: they hold a copy of
the identifier, which points to the same object.
(hat tip to #tomzx)
You'll likely do better to rearchitect your code to deal with this or use a language whose default behavior is call-by-value like C or Java.
Since objects are passed by reference by default now, is there maybe some special case when &$obj would make sense?
Objects use a different reference mechanism. &$object is more a reference of a reference. You can't really compare them both.
See Objects and references:
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
&$object is something else than $object. I'll give you an example:
foreach ($objects as $object) {
if ($cond) {
$object = new Object(); // This won't affect $objects
}
}
foreach ($objects as &$object) {
if ($cond) {
$object = new Object(); // This will affect $objects
}
}
I won't answer the question if it makes sense, or if there is a need. These are opinion based questions. You can definitely live without the & reference on objects, as you could without objects at all. The existence of two mechanisms is a consequence of PHP's backward compatibility.
There are situations where you add & in front of function name, to return any value as a reference.
To call those function we need to add & in front of object.
If we add & in front of object, then it will return value as reference otherwise it will only return a copy of that variable.
class Fruit() {
protected $intOrderNum = 10;
public function &getOrderNum() {
return $this->intOrderNum;
}
}
class Fruitbox() {
public function TestFruit() {
$objFruit = new Fruit();
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 10
$intOrderNumber = $objFruit->getOrderNum();
$intOrderNumber++;
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 10
$intOrderNumber = &$objFruit->getOrderNum();
$intOrderNumber++;
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 11
}
}
I've read up about PHP variable references but I'm not 100% and was hoping someone could help.
If I have a class like the following:
class Item
{
public $value;
}
I then have an array of those items in a variable - lets call that $items. All I did was new Item()...and $items[] = $newItem;.
Now, I want to populate another array but it filters the original array based on its value. So like the following:
foreach($items as $key => $value)
{
$filteredItems[] = &value;
}
Now, I have ANOTHER variable that iterates over that filtered list and does something like so:
$theItem = $filteredItems[10];
$theItem->value = 100;
Now this is where I'm confused. Do I need to set $theItem to &filteredItems[10]; (reference) or will it just know that the value in the array is a reference type and $theItem also becomes a reference to that same item? I'm after that last set of $theItem->value = 100; changes the very original object stored in the $items list.
In PHP 5 objects are always passed around by their "handle" for lack of better word. This means if you do this:
$a = new Item();
$a->value = 1;
$b = $a;
$b->value++;
echo $a->value;
The value of 2 is echoed. Why? Because the handle of the object is copied from $a to $b and they both point to the same object. This isn't a reference in terms of using &, but behaves similarly enough to the point that people generally call it the same thing... even though it's not.
So you do not need any use of references in your code. Usually in PHP, you never need to use references when using objects.
With respect to objects, you really only notice references if you do this (assign a new value to the variable itself):
function foo(Item &$a)
{
$a = null;
}
$b = new Item();
foo($b);
var_dump($b);
This results in NULL, which wouldn't happen without a reference. But again, this is not typical usage, so you can really forget about using references with objects.
(And of course the use of a function isn't necessary here to illustrate the point, but that's the most typical place you'll see them in the "real world.")
It's like this:
foreach($items as $key => &$value) {
$filteredItems[] = $value;
}
The point where you give the original instance into a different scope is where you put the &.
Same is for functions:
function myFunction(&$variable) { }
Example:
<?php
class test {
public $testVar;
public function __construct() {
$this->testVar = "1";
}
}
function changeByReference(&$obj) {
$obj->testVar = "2";
}
$instance = new test();
// Prints 1
echo $instance->testVar, PHP_EOL;
changeByReference($instance);
// Prints 2
echo $instance->testVar, PHP_EOL;
Read more about it here: http://php.net/manual/en/language.oop5.references.php
If you want to copy an instance, use clone - php.net/clone
The easiest way to get it is when you know the difference between these: class, object and instance. (I'd explain it more at this point but it would only confuse you more because my english is not accurate enough for now to explain the details enough.)
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"
Suppose I have an array of a objects of user defined class. Wanted to know how do I extract the elements of the array in PHP.
// class definition
class User
{
public $fname;
public $lname;
}
// array of objects of the class defined above
$objUser1 = new User():
$objUser2 = new User():
$objUser3 = new User():
$objUser4 = new User():
$alUser = array();
$alUser[] = $objUser1;
$alUser[] = $objUser2;
$alUser[] = $objUser3;
$alUser[] = $objUser4;
// trying to iterate and extract values using typcasting - this does not work, what is the alternative.
foreach($alUser as $user)
{
$obj = (User) $user; // gives error - unexpected $user;
}
Thats how I used to do in java while extracting objects from the Java ArrayList, hence thought the PHP way might be similar. Can anyone explain it.
foreach ($alUser as $user) {
$obj = $user;
}
Why do you need typecasting for this?
PHP is a dynamically typed language. There is no need to cast in most cases.
It is impossible to cast to a User: see PHP's documentation on type juggling and casting.
This example would print "$user is a object (User)" four times.
foreach($alUser as $user) {
echo '$user is a ' . get_type($user);
if(is_object($user)) {
echo ' (' . get_class($user) . ')';
echo "\n";
}
It would be nice for example Eclipse PDT to determine the type of object for Code Completion. otherwise you are stuck backtracing, where the array was created and what objects were put into it and then look at the class file to see what functions are available (or temp create a new theObject() to see what methods/properties are available if you know what type of object it is. other times may not be as easy if many objects call functions that create those arrays and objects in them, so have to backtrace to see how those arrays made). Heard a few other IDE's may be able to determine type better like phpEd possibly?