Very new to OOP so please bear with me. I have a method that checks characteristics of a persons array and has a counter to keep track of things. The persons array starts off as serialized data, which I'm converting to an array with the unzerialize() function. When I do var_dump($this->people) in the constructor, I get the correct values. When I do the same in any of the other methods in the class, the array is duplicated a number of times and my counter produces incorrect values.
Also doing echo gettype($this->people) in the constructor results in array as expected, but in the other methods results in arrayarrayarrayarray....
What could be causing this duplication? And how do I solve it?
* EDIT *
Sorry for the confusion. I did not know where the problem was so it was difficult for me to explain properly.
The problem is not with my class definition, but how I am using the object. I have reworked the code to illustrate. I thought that once the object was instantiated, the values produced by it would be set, however it turns out that each time I call the get_results() method, $this->num is incremented and the value is persisted.
So my question is, how do I run the get_results() method once, and access the results[] array without changing the values? I was hoping I could do something like if($nums['results']['num'] == 1) but that results in a fatal error.
class DoStuff
{
private $num;
public $results;
public function __construct($val)
{
$this->num = $val;
$this->results = [];
}
private function compute_num()
{
$this->num++;
$this->results['num'] = $this->num;
return $this->results;
}
public function get_results()
{
$this->results = $this->compute_num();
return $this->results;
}
}
$nums = new DoStuff(0);
$nums->get_results();
if($nums->get_results()['num'] == 1)
{
printf('<p>(if) Num is: %d</p>', $nums->get_results()['num']);
}
else
{
printf('<p>(else) Num is: %d</p>', $nums->get_results()['num']);
}
// Prints (else) Num is: 3
Ok, so I was trying to access an object as an array. The solution is to use get_object_vars() after running the get_results() method.
$nums = new DoStuff(0);
$nums->get_results();
$nums = get_object_vars($nums);
if($nums['results']['num'] == 1)
{
printf('<p>(if) Num is: %d</p>', (int) $nums['results']['num']);
}
else
{
printf('<p>(else) Num is: %d</p>', (int) $nums['results']['num']);
}
// Prints: (if) Num is: 1
Related
I'm getting stuck with maybe a simple question. I created a new class with many calculations inside. I have a recursive array to dynamically generate SQL from a Die result. When the result is between a given range, I'll have to do an extra operation.
I've got this multi-dimensional array to fill with the value of my dice, using an array of IDs as my first "key":
$this->multidim[$id_object][]
I was thinking about creating another function to populate it, but I'm unsure how to build it correctly. The specifications of this function I need are the following:
I need to call a function with the multidimensional array, and
If the result is 100, I need to re-roll the dice twice, and check the result again
$this->checkresult($id_obj, $die);
function checkresult($id_obj, $die)
{
if ($die == 100){
$rand1 = $this->launchDie(1, 100);
$rand2 = $this->launchDie(1, 100);
if($this->checkresult($array, $rand1)) {
if($this->checkresult($array, $rand2)) {
return 1;
}
}
} else {
if (!isset($array[$tiro])) {
$this->multidim[$id_obj][$die] = 1;
}
return 1;
}
}
Is this approach correct? I feel uncomfortable not returning a "real" value, but as I said I need to re-call that function recursively.
You can return the rolled value like this:
public function addResult($object_id, $result)
{
$this->multidim[$object_id][] = $result;
}
public function checkResult($object_id)
{
$roll = $this->launchDie(1, 100);
if ($roll == 100) {
$additionalRoll = $this->checkResult($object_id);
$this->addResult($object_id, $additionalRoll);
$roll = $this->checkResult();
}
return $roll;
}
And call it like this:
$this->addResult($object_id, $this->checkResult($object_id));
This way each time a 100 is rolled there will be two rolls instead of the one. Please note that this could go on forever (improbable, though ;)).
Also note that I changed the structure of your multidim array, as it made more sense to me that way, you may need to change that back if it doesn't match what you would like to achieve.
This may seem like a simple question but I have searched for an answer and come across call backs and a few different things but surely there is a simple way to do this.
I have a function in a class
that uses an iterative process so i end up with an array:
$msg[$i]
I want to exit the function with that array returned to main script
exit($msg[])
but will only return for example $msg[1] or $msg[$i] the last iteration I'd like to get the whole array without manually typing each one defeats the point of the iterative process
use return instead exit
return $msg;
have you tried using return $msg; ?
In order to return an array, you return the variable name of the array. This is really a pointer to the first element in the array.
This is an example of how to return an array:
function dofoo() {
$msg["a"] = "Foo";
$msg["b"] = "Bar";
$msg["c"] = "Baz";
return $msg;
}
$returned_array = dofoo();
Under the hood what happens is: return $msg; returns a pointer to the first element of the array. $returned_array = dofoo(); allocates enough memory for the returned array and stores it in $returned_array.
My current way:
class A {
public function function_b($myint) {
if (!is_numeric($myint)) return false;
// code ...
}
}
I would like to abandon the function is_numeric() like this:
public function function_b(Integer $myint) {
// code ...
}
It works with arrays like this:
public function function_c(Array $arr) {
// only executes following code if $arr is an array / instance of Array!
}
Note: the function has to return false if the value isn't a number (int)! I don't want to cast it.
How would you short my current code? Thanks in advance!
You can't force strict types in function prototypes in PHP inherently, because it's not a strictly typed language. PHP is a weakly typed language and trying to go against the grain will only hurt you in many situations. Also, is_numeric does not guarantee that your value is of type int (for what it's worth).
What you can do is analyze your need for why you think this approach is necessary in the first place and decide on how to best implement this without creating potential for bugs.
For example, take the following scenario where what your method expects is an ID for a database query.
class MyClass {
public function getUser($id) {
if (!is_int($id)) {
throw new Exception("Invalid argument supplied. Expecting (int), but argument is of type (" . gettype($id) . ").");
}
// Otherwise continue
$db = new PDO($dsn);
$stmt = $db->prepare("SELECT username FROM users WHERE user_id = ?");
$stmt->execute(array($id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
$MyObject = new MyClass;
$result = $MyObject->getUser($_POST['id']);
/* The problem here is $_POST will always be of type string. */
What this should tell you is that it makes no sense to force type checking here since PHP will have done the right thing for you had you just let it alone.
The question you need to be asking yourself is not "How do I force strict typing?", but rather "Why would I need to force strict typing at all?".
You should look into typecasting:
http://php.net/manual/en/language.types.type-juggling.php#language.types.typecasting
Just use (int) when accessing the value to typecast it to an integer.
You could just typecast it:
public function function_b($myint) {
$myint = (int) $myint;
}
Or better yet add a public setter to class A which will do it for you every time you set the value:
class A
{
public function setMyInt($myInt)
{
$this->myInt = (int) $myInt;
}
}
-- Update (based on comment) --
class A
{
public function doSomethingWithAnArray(array $array)
{
....
}
}
Notice the keyword array in the signature of the doSomethingWithAnArray method, now if you don't pass an array to this function PHP will throw a fatal error and cease code execution. This is known as typehinting, and can be applied to objects as well.
function needsInteger($int) {
if (((int) $int) != $int) return false;
// ...
}
The advantage here is that you can still accept loosely typed parameters, but the non-strict equality check against the cast value will yield an acceptable result.
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.
First of all, I apologize that this question is so vague. I can't remember what this is called, or how they work, so it's very difficult to start searching or formulate a good title.
I have two questions wrapped into one:
First:
How are objects converted to other types internally? What is this called?
Example:
$Obj{
$value = 1;
$other = 2;
$more = 3;
}
$myObj = (string)$Obj;
print $myObj; // prints "1, 2, 3" or something like that
Second:
Can this method be used in math? Is there some override function that recognizes when an Object is being used in math?
Example:
$Obj{
$value = 1;
$other = 2;
$more = 3;
}
$result = 4 / $Obj;
print $result; // prints ".66666667" or something similar (sum of all properties)
Update:
I think it might have something to do with serialize(), but I know I've heard of a case where this is done "automatically" without having to call serialize() and it's done in a way that doesn't actually serialize the whole object, it just converts it to a useable value, like my above examples.
Final:
Thanks for #trey for being right about it being casting and to #webbiedave for pointing me to the magic method __toString.
It is casting as you can define the magic method __toString to allow the object to be cast to a string as desired, which will then allow PHP to cast it to an int or float in math.
Take the following example:
class A
{
public $value = 1;
public $other = 2;
public $more = 3;
public function __toString()
{
return (string)($this->value + $this->other + $this->more);
}
}
$obj = new A();
echo 4 / (string)$obj; // outputs 0.66666666666667
It's called type casting when you change an object to a different data type, as for the second part, I'm not entirely sure I understand you, are you trying to type cast during a math function?
it sounds like this may be more along the lines of what you're looking for:
class User
{
public $first_name='John';
public $last_name='Smith';
public function __toString()
{
return "User [first='$this->first_name', last='$this->last_name']";
}
}
$user=new User;
print '<span>'.$user.'</span>';
but I'm unable to find documentation about how to make this work when the object is converted to an interger... I'll update if I do