Using arrays in classes PHP - php

I'm experimenting with classes and objects for the first time and I thought I'd make a template for a Box that can store things like Books. (Thinking in terms of real-world items)
<?php
function feetToInches($feet){
$feet = $feet * 12;
return $feet;
}
class Book{
var $l = 6;
var $w = 5;
var $h = 1;
}
class Box{
//This is a box. It has length, width, and height, and you can put things in it.
var $length = 0;
var $width = 0;
var $height = 0;
var $storedArray = array();
function setDimensions($l, $w, $h){
$this->length = feetToInches($l);
$this->width = feetToInches($w);
$this->height = feetToInches($h);
}
function storeThings($thing){
$this->storedArray[] = $thing;
}
function getThings(){
return $this->storedArray;
}
}
$thatBook = new Book;
$BookBox = new Box;
$BookBox->setDimensions(6,5,1);
for($i = 0; $i < 5; $i++){
$BookBox->storeThings($thatBook);
}
echo $BookBox->getThings() . "<br />";
/*
foreach($BookBox->getThings() as $item){
echo $item;
}
*/
var_dump($BookBox);
?>
So what I have is simple here, you have boxes of a dimension, and you throw books of a fixed dimension in them.
Putting things in it is no problem, but when I try to retrieve them, I either get errors or nothing happens. And when I try to specify a key for the array like
echo $BookBox->getThings()[2];
I get an error that it's not an array or something.
So can someone please point me in the right direction here?
And normally the class would be a separate file, but I'm just learning here.

What version of PHP are you using.
Array dereferencing (referencing into a returned array) was only added in PHP 5.4.
If you're using a previous version, you'd have to do this:
$books = $BookBox->getThings();
echo $books[2];
Edit
Since you are pushing Books into a box, $books[2] returns you an instance of the Book object. Echo is used to output a string, hence the error.
You can either echo a particular property of the book, or print out all of the properties by doing:
print_r($books[2]);

First, you cannot do echo since what you'll get is not a string but an object. Use print_r() or var_dump() instead.
Second, just like the other answers here, you should do this.
$books = $BookBox->getThings();
print_r($books[2]);
But I suggest you to make getThings() accept a variable for getting a specified array element:
function getThings($key = null) {
if ($key) {
return isset($this->storedArray[$key]) ? $this->storedArray[$key] : null;
} else {
return $this->storedArray;
}
}
// Then you can do this
// print_r($BookBox->getThings(2));

What you are calling when you call $BookBox->getThings() is actually an object and not an array.
You might try something along the lines of:
$books = $BookBox->GetThings();
echo $books[2];

Related

How to declare an array of objects for a for loop in PHP?

I want to insert the details of a quiz in which among a lot of strings (question, professor, course, etc) , I have one array of answers (and its corresponding array of is_correct), so I thought of creating a for loop to insert each answer properly.
The problem is I don't know how to correctly call the questionQuiz object. I noticed if I declare two different objects at the beginning and then do this manually:
$questionQuiz1 -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[0],$is_correct[0]);
$questionQuiz2-> insert_question($quiz_name,$professor,$course,$question,$points,$answer[1],$is_correct[1]);
it works.
How should I declare this object as an array and use it in an iteration?
I tried something like this but it isn't correct.
$questionQuiz[] = new Test();
if(isset($_POST['quiz_name'],$_POST['professor'],$_POST['course'],$_POST['question'],$_POST['points'],$_POST['answer'], $_POST['is_correct'])) {
$quiz_name = $_POST['quiz_name'];
$professor = $_POST['professor'];
$course = $_POST['course'];
$question = $_POST['question'];
$points = $_POST['points'];
$answer = $_POST['answer'];
$is_correct = $_POST['is_correct'];
if(!empty($quiz_name) && !empty($professor)&& !empty($course)&& !empty($question)&& !empty($points)&& !empty($answer) && !empty($is_correct)){
for($i=0; $i<count($answer); $i++) {
$questionQuiz[$i] -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[$i],$is_correct[$i]);
}
}else{
echo json_encode("param must not be empty");
}
}
Should I instantiate $questionQuiz[] = new Test(); inside the loop? I tested and it seems to work, is it correct to do it this way?
So the problem in your code, is that you only create 1 instance of Test class (at the top). And inside your for loop, you only reference it and call the insert_question method on it. Beware: in this case only $questionQuiz[0] exists, so in the other cases nothing happens (or an error might occur).
Option 1
If you only want to call the method on the Test class, you could call it in your for loop like this:
(new Test())->insert_question( ... etc ... );
Option 2
If you want to store the created class objects, you create a new Test object, call the insert_question method on it and add the object to your array:
$object = new Test();
$object->insert_question( ... etc ...);
$questionQuiz[] = $object;
You seem to have the logic all laid out, your just not doing what you're saying.
Create an array, and then add a new object to that array each time through the loop.
$questionQuiz[] = array();
if(isset($_POST['quiz_name'],$_POST['professor'],$_POST['course'],$_POST['question'],$_POST['points'],$_POST['answer'], $_POST['is_correct'])) {
...
for($i=0; $i<count($answer); $i++) {
$questionQuiz[$i] = new Test();
$questionQuiz[$i] -> insert_question($quiz_name,$professor,$course,$question,$points,$answer[$i],$is_correct[$i]);
}
...
I will note however, that something seems off about having a function called insert_question() where you individually insert single answers options on seemingly multiple-choice questions. I would think you would pass an array of answer options with corresponding correctness.
You mentioned storing the posts to an object array. would something like this work?
<?php
if(isset($_POST['quiz_name'], $_POST['professor'], $_POST['course'], $_POST['question'], $_POST['points'], $_POST['answer'], $_POST['is_correct']))
{
$quiz_name = $_POST['quiz_name'];
$professor = $_POST['professor'];
$course = $_POST['course'];
$question = $_POST['question'];
$points = $_POST['points'];
$answer = $_POST['answer'];
$is_correct = $_POST['is_correct'];
}
if(!empty($answer_array) && count($answer_array[5]) > 0)
{
$count = count($answer_array[5]);
$questionQuiz[] = new Test();
for($i=0; $i < $count; $i++)
{
//assuming your class is correct and you'll need to have it handle the incoming array how you want it to
$answer_array = array($quiz_name, $professor, $course, $question, $points, $answer[$i], $is_correct[$i]);
$questionQuiz[$i] -> insert_question($answer_array);
}
}
else
{
echo "param must not be empty";
}
?>

Add new member to a variable in an array

I want to append new member to element which is in an array. Without array it's simple to write. for example:
$exp["app_form_id"] = $form_id;
But when I want add new member 'app_form_id' to all object of an array it not insert them and also there's not any error with them. I tried do it by 2 way, but none of them not worked:
1)
foreach ($exps as $exp) {
$exp["app_form_id"] = $form_id;
}
2)
for ($i = 0; $i < count($exps); $i++) {
$exps[i]["app_form_id"] = $form_id;
}
Your #1 method will work if you pass by reference (&):
foreach ($exps as &$exp) {
$exp["app_form_id"] = $form_id;
}
Try like this,
foreach ($exps as &$exp) {
$exp->app_form_id = $form_id;
}
I feel you are having manipulation with an object.
Give it a try, it should work.
Whatever you are changing inside block is limited to the block and not changing back, Try like this
$newExps = array();
foreach ($exps as $exp) {
$exp["app_form_id"] = $form_id;
$newExps[] = $exp;
}
print_r($newExps);

Building chained function calls dynamically in PHP

I use PHP (with KirbyCMS) and can create this code:
$results = $site->filterBy('a_key', 'a_value')->filterBy('a_key2', 'a_value2');
This is a chain with two filterBy. It works.
However I need to build a function call like this dynamically. Sometimes it can be two chained function calls, sometimes three or more.
How is that done?
Maybe you can play with this code?
chain is just a random number that can be used to create between 1-5 chains.
for( $i = 0; $i < 10; $i ++ ) {
$chains = rand(1, 5);
}
Examples of desired result
Example one, just one function call
$results = $site->filterBy('a_key', 'a_value');
Example two, many nested function calls
$results = $site->filterBy('a_key', 'a_value')->filterBy('a_key2', 'a_value2')->filterBy('a_key3', 'a_value3')->filterBy('a_key4', 'a_value4')->filterBy('a_key5', 'a_value5')->filterBy('a_key6', 'a_value6');
$chains = rand(1, 5)
$results = $site
$suffix = ''
for ( $i = 1; $i <= $chains; $i ++) {
if ($i != 1) {
$suffix = $i
}
$results = $results->filterBy('a_key' . $suffix, 'a_value' . $suffix)
}
If you are able to pass 'a_key1' and 'a_value1' to the first call to filterBy instead of 'a_key' and 'a_value', you could simplify the code by removing $suffix and the if block and just appending $i.
You don't need to generate the list of chained calls. You can put the arguments of each call in a list then write a new method of the class that gets them from the list and uses them to invoke filterBy() repeatedly.
I assume from your example code that function filterBy() returns $this or another object of the same class as site.
//
// The code that generates the filtering parameters:
// Store the arguments of the filtering here
$params = array();
// Put as many sets of arguments you need
// use whatever method suits you best to produce them
$params[] = array('key1', 'value1');
$params[] = array('key2', 'value2');
$params[] = array('key3', 'value3');
//
// Do the multiple filtering
$site = new Site();
$result = $site->filterByMultiple($params);
//
// The code that does the actual filtering
class Site {
public function filterByMultiple(array $params) {
$result = $this;
foreach ($params as list($key, $value)) {
$result = $result->filterBy($key, $value);
}
return $result;
}
}
If filterBy() returns $this then you don't need the working variable $result; call $this->filterBy() and return $this; and remove the other occurrences of $result.

Multiple returning

Could anyone help me.
I need to return multiple img's, but with this code, only one of two is returning.
What is the solution.
Thank you in advance.
$test = "/claim/img/box.png, /claim/img/box.png";
function test($test)
{
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas = "<img src=".$photo[$i].">";
return $returnas;
}
}
This might be a good opportunity to learn about array_map.
function test($test) {
return implode("",array_map(function($img) {
return "<img src='".trim($img)."' />";
},explode(",",$test)));
}
Many functions make writing code a lot simpler, and it's also faster because it uses lower-level code.
While we're on the subject of learning things, PHP 5.5 gives us generators. You could potentially use one here. For example:
function test($test) {
$pieces = explode(",",$test);
foreach($pieces as $img) {
yield "<img src='".trim($img)."' />";
}
}
That yield is where the magic happens. This makes your function behave like a generator. You can then do this:
$images = test($test);
foreach($images as $image) echo $image;
Personally, I think this generator solution is a lot cleaner than the array_map one I gave earlier, which in turn is tidier than manually iterating.
Modify your code that way
function test($test)
{
$returnas = '';
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas .= "<img src=".$photo[$i].">";
}
return $returnas;
}
Your code didn't work since you were returning inside the loop immediatly. Every programming language support "only a return for call". In my solution you're appendig a string that has an img tag each time you enter the loop and return it after every photo is "passed" into the loop
You could even use the foreach() construct, of course
Bonus answer
If you don't know the difference between ...
for ($i = 0; $i < count($photo); $i++)
and
for ($i = 0, $count = count($photo); $i < $<; $i++)
Well, in first case you'll evaluate count($photo) every single time the for is called whereas the second time, it is evaluated only once.
This could be used for optimization porpuses (even if php, internally, stores the length of an array so it is accesible in O(1))
The function breaks after the first return statement. You need to save what you want to return in some structure, an array eg, and return this.
function test($test)
{
$result = array();
$photo = explode(',', $test);
for ($i = 0; $i < count($photo); $i++)
{
$returnas = "<img src=".$photo[$i].">";
$result[] = $returnas;
}
return $result;
}

Php index of element in the array, update element

for some reason $post is always < 0. The indoxOf function works great. I use it on ohter codes and it works great
for some reason even after I add the element like this array_push($groups, $tempDon); on the next loop i continues to return -1
$donations = $this->getInstitutionDonations($post->ID);
$groups=array();
foreach( $donations as $don ) : setup_postdata($don);
$pos = $this->indexOf($don, $groups);
print_r($pos);
if($pos < 0)
{
$tempDom = $don;
$tempDon->count = 1;
array_push($groups, $tempDon);
}
else
{
$tempDom = $groups[$pos];
$tempDon->count++;
array_splice($tempDon);
array_push($groups, $tempDon);
echo '<br><br><br>ahhhhhhhhhh<br><br>';
}
endforeach;
protected function indexOf($needle, $haystack) { // conversion of JavaScripts most awesome
for ($i=0;$i<count($haystack);$i++) { // indexOf function. Searches an array for
if ($haystack[$i] == $needle) { // a value and returns the index of the *first*
return $i; // occurance
}
}
return -1;
}
This looks like an issue of poor proofreading to me (note $tempDom vs $tempDon):
$tempDom = $don;
$tempDon->count = 1;
array_push($groups, $tempDon);
Your else block has similar issues.
I also completely agree with #hakre's comment regarding syntax inconsistencies.
EDIT
I'd also like to recommend that you make use of PHP's built-in array_search function in the body of your indexOf method rather than rolling your own.

Categories