I’m a total new to PHP and I’m having a logic problem in my code (array_rand($arrCards,1) is running out of elements before it should, I think). So I’ve done a var_dump of the array and I get this output (brief excerpt):
array (size=52) 0 => object(Card)[2] private 'suit' => string 'heart' (length=5) private 'rank' => string 'a' (length=1) 1 => object(Card)[3] private 'suit' => string 'heart' (length=5) private 'rank' => string '2' (length=1) 2 => object(Card)[4] private 'suit' => string 'heart' (length=5) private 'rank' => string '3' (length=1)
Here’s my Card class:
class Card { //properties private $suit; private $rank; //constructor public function __construct($r, $s) { $this->rank = $r; $this->suit = $s; } //methods public function getSuit() { return $this->suit; } public function getRank() { return $this->rank; } }
And here is how I create each card and push it into each array (this is the Deck class constructor):
//constructor public function __construct() { $this->arrCards = array(); $objCard = new Card("a", "heart"); array_push($this->arrCards, $objCard); $objCard = new Card("2", "heart"); array_push($this->arrCards, $objCard); $objCard = new Card("3", "heart"); blah blah continued...
(It’s been pointed out to me that I could have constructed the Deck using two for loops, but I’ve typed it all out now so that probably doesn’t matter.)
Here’s the relevant methods in the Deck class:
//methods public function dealCard() { if ($this->hasCard()) { echo $this->intCount . PHP_EOL; $index = array_rand($this->arrCards, 1); $card = array_splice($this->arrCards,$index); return $card[0]; } else { return Null; } } protected function hasCard() { if ($this->intCount > 0) { return true; } else { return false; } }
Here’s the error I get (preceded by the echo $this->intCount; (note how it’s not actually removing the card from the deck like I intend it to either):
52 52 52 52 ( ! ) Warning: array_rand(): Second argument has to be between 1 and the number of elements in the array in C:/wamp64/www/ofc/ofc_classes.php on line 162 Call Stack # Time Memory Function Location 1 0.0000 240704 {main}( ) .../main.php:0 2 0.0010 348080 Deck->dealCard( ) .../main.php:11 3 0.0010 348176 array_rand ( ) .../ofc_classes.php:162
array_rand will return a random key from your input array, while
array_splice with the offset positive, will remove that many elements from the array starting from the beginning of the array.
Example:
$deck = ['A','K','Q','J','10','9','8','7','6','5','4','3','2','1']; $card = array_rand($deck,1); print $card . PHP_EOL; // let's assume it outputs 9, this is the key from the array // array_rand returns a random key from the input array $remainingDeck = array_splice($deck,$card); print_r($remainingDeck) . PHP_EOL; // will output Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )
Which is not what you expect, we have eliminated 9 cards from the deck, instead of just one.
The warning you get is telling you that, after a couple of dealt cards, your deck is empty.
You can easily verify this by printing out the count of the $this->arrCards after dealing each card instead of relying on $this->intCount which does not get updated after dealing the cards.
I’d probably change the dealCard() and hasCard() methods:
public function dealCard() { $result = null; if ($this->hasCard()) { $index = array_rand($this->arrCards, 1); $card = array_splice($this->arrCards, $index, 1); $result = $card[0]; } return $result; } public function hasCard() { $result = (!empty($this->arrCard)); return $result; }
what and why:
- I like using $result for a method/function – you always know $result is what you are expecting to be returned
- initialise the $result – if the code doesn’t behave as you expect it to
you’ll always get something returned - use array_splice() function with the length parameter – you only need 1 card from the deck
- 1 exit point to the method – this is a simple method, but more complicated ones with multiple exit (return) points can be difficult to debug later
- use empty() function to check if there are more cards – it saves using/maintaining a counter of cards in the deck