PHP: Is code like this possible? - php

I'm trying to have a user-defined list of game-maps. Because I don't know how many maps will be in the array at design time, I'm trying to dynamically create new variables to contain them. Is this even possible? Here's my failed attempt:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
?>
Parser says: Fatal error: Cannot access empty property
Is something like this even feasible in this manner?

There are some errors in your code:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
Since you are on the global scope here, not inside a function, there is no need for global.
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
Is some code missing here? You are not using $element within the loop, so this assignment is not needed.
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
The syntax to access a member variable is $object->variable, not $object->$variable. The latter one will evaluate $variable and use the value as variable name (E.g., if $variable = "foo", this will try to access $object->foo).
Use $map[$i]->played = $x++; instead.

When accessing the properties of a class, you don't want to use the $ in front of the property name itself.
Replace $map[$i]->$played = $x++; with $map[$i]->played = $x++; to solve the Fatal error: Cannot access empty property error.

You could override the magic methods to provide dynamic properties if you wish:
public function __get($name)
{
...
}
public function __set($name, $value)
{
...
}
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
Within each of these functions you could store the data in some internal array structure.

You don't have to use the $ when accessing properties of an instance. Simple use $map[$i]->played. Have a look on the OOP basics.

Related

Is there ever a need to use ampersand in front of an object?

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
}
}

PHP Object References?

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.)

How to Pass Class Variables in a Function Parameter

The main function of the example class uses the reusableFunction twice with different data and attempts to send that data to a different instance variable ($this->result1container and $this->result2container) in each case, but the data doesn't get into the instance variables.
I could get it to work by making reusableFunction into two different functions, one with array_push($this->result1container, $resultdata) and the other with array_push($this->result2container, $resultdata), but I am trying to find a solution that doesn't require me to duplicate the code.
My solution was to try to pass the name of the result container into the function, but no go. Does somebody know a way I could get this to work?
Example Code:
Class Example {
private $result1container = array();
private $result2container = array();
function __construct() {
;
}
function main($data1, $data2) {
$this->reusableFunction($data1, $this->result1container);
$this->reusableFunction($data2, $this->result2container);
}
function reusableFunction($data, $resultcontainer) {
$resultdata = $data + 17;
// PROBLEM HERE - $resultcontainer is apparently not equal to
// $this->result1container or $this->result2container when I
// try to pass them in through the parameter.
array_push($resultcontainer, $resultdata);
}
function getResults() {
return array(
"Container 1" => $this->result1container,
"Container 2" => $this->result2container);
}
}
(If this is a duplicate of a question, I apologize and will happily learn the answer from that question if somebody would be kind enough to point me there. My research didn't turn up any answers, but this might just be because I didn't know the right question to be searching for)
It looks to me like you want to be passing by reference:
function reusableFunction($data, &$resultcontainer) {
...
If you don't pass by reference with the & then you are just making a local copy of the variable inside reuseableFunction .
You are changing the copy, not the original. Alias the original Array by referenceDocs:
function reusableFunction($data, &$resultcontainer) {
# ^
And that should do the job. Alternatively, return the changed Array and assign it to the object member it belongs to (as for re-useability and to keep things apart if the real functionality is doing merely the push only).
Additionally
array_push($resultcontainer, $resultdata);
can be written as
$resultcontainer[] = $resultdata;
But that's just really FYI.
You may pass the attributes name as a String to the method like this:
function reusableFunction($data, $resultcontainer) {
$resultdata = $data + 17;
array_push($this->{$resultcontainer}, $resultdata);
}
//..somewhere else..
$this->reusableFunction($data, 'result2Container')
Some php experts wrote some texts about "why you shouldn't use byReference in php".
Another solution would be to define the containers as an array. Then you can pass an "key" to the method that is used to store the result in the array. Like this:
private $results = array();
function reusableFunction($data, $resIdx) {
$resultdata = $data + 17;
array_push($this->$results[$resIdx], $resultdata);
}
//..somewhere else..
$this->reusableFunction($data, 'result2Container');
//..or pass a number as index..
$this->reusableFunction($data, 1);

How to make differently indexed PHP arrays point to the same objects

Within a class I have three arrays (as instance variables) that must all point to the same objects. The first is a numerically indexed array that I get back from some external function. The second array must index the same objects by their name. The third by some other property. This is for fast access via those properties. So the point is: it shouldn't matter which array I use to access an object and modify it.
Yet it can't make it happen. I know about PHP references. I know about java references. I know about C pointers, but I can't make it happen - wherever I try to place the ampersand (=&).
class xxx {
private $objs;
private $objsByName;
public function __construct() {
$this->objs = getObjs();
$this->objsByName = array();
foreach($this->objs as $obj) {
$this->objsByName[$obj->getName()] = $obj;
}
}
}
There is no place here where I have not tried replacing = with =&
I am missing something?
Replace your foreach loop with this one.
for($i = 0 , $n = count($this->objs); $i < $n ; $i ++){
$this->objsByName[$this->objs[$i]->getName()] = &$this->objs[$i];
}
This will solve your problem :)
Thanks!
Hussain.
In PHP, objects are always passed by reference (you cannot copy an object unless you use clone keyword). This code illustrates this:
<?php
class AnObject{
private $name;
public $count=0;
public function __construct($name){
$this->name = $name;
}
public function getName(){
return $this->name;
}
}
function getObjs(){
return array(
new AnObject('One'),
new AnObject('Two'),
new AnObject('Three'),
);
}
class xxx {
private $objs;
private $objsByName;
public function __construct() {
$this->objs = getObjs();
$this->objsByName = array();
foreach($this->objs as $obj) {
$this->objsByName[$obj->getName()] = $obj;
}
}
public function alterAnObjectByName($name){
$this->objsByName[$name]->count++;
}
}
$x = new xxx;
var_dump($x);
$x->alterAnObjectByName('Two');
var_dump($x);
The issue is probably somewhere else.
Mark this part from the php manual:
http://php.net/manual/en/control-structures.foreach.php
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
So your $obj is a copy.
I have not tested Hussain's code, but that looks like a good option :)
PHP always use copy on write functions, chances are that your objects will be same until one is changed.
To avoid errors you should say that one of your array contains the data and that thee others are just indexes.
Use the index to find the id, and use tha data array, indexed by id, to read and alter data.
In PHP5 you can add & to the as variable to make the foreach loop not clone the object:
foreach($this->objs as &$obj) {
$this->objsByName[$obj->getName()] = &$obj;
}
Reference: http://php.net/manual/en/control-structures.foreach.php
p/s: I'm not sure if the & inside the foreach body is needed or not but just add it to be safe. Or you can try removing it to see if it's needed or not.

How to access class members from an array of class variables?

I want to use PHP's reflection features to retrieve a list of parameter names from a method. I have a class like this:
class TestClass {
public function method($id, $person, $someotherparam) {
return;
}
}
I can get the list using code like this:
$r = new ReflectionClass('TestClass');
$methods = $r->getMethods();
foreach($methods as $method) {
$params = $method->getParameters();
$p = $params[0]; // how can I combine this and the next line?
echo $p->name;
I want to know how to access the class members from the array, so I don't have to do an assignment. Is this possible? I tried something like echo ($params[0])->name but I get an error.
you can replace these two lines :
$p = $params[0]; // how can I combine this and the next line?
echo $p->name;
by that single one :
echo $params[0]->name;
i.e. no need for any kind of parenthesis here.
But you cannot use this kind of syntax :
($params[0])->name
It'll give you a
Parse error: syntax error, unexpected T_OBJECT_OPERATOR

Categories