...

View Full Version : object type session variables?



ASAAKI
04-03-2003, 03:11 PM
can objects be passed across pages as session variables?
like, i have an object class called mcq. its properties are question, a, b, c, d, e, ans. kind of like so:
class mcq{
...
$this->question = "What color is the sky?";
$this->a = "Red";
$this->b = "Blue";
$this->c = "Green";
$this ->ans="b";
....
}
and it has a method that returns whether the user's answer is correct or not, by comparing the user's answer with $this->ans. this method is called "correctAns".

on mcq1.php, the user answers some MCQs, each question is actually a member of the mcq object array. so that mcq[0] is the first question object (with a,b,c, the correct answer,etc), and mcq[1] is the second object with all its properties, and so on.

on submitting, the user is directed to mcq2.php, where his/her results are displayed. I want to pass the mcq objects' array as a session variable from mcq1.php to mcq2.php, so that on mcq2.php page i can check each object's own answer with the user's answers submitted in the previous form.
using a loop to get the mcq objects works without any errors.


for($i = 0; $i < $no_mcqs; $i++){
eval("\$mcq[".$i."] = \$_SESSION['mcq[".$i."]'];");
}


but when i try to print out, say, $mcq[0]->ans, i don't get anything.
and if i want to check the user's first answer using :
$result = $mcq[0]->correctAns($user_answer[0]);
i get this error:
Fatal error: Call to a member function on a non-object in c:\phpdev\www\learning\mcq2.php on line 69

apparently, $mcq[0] did get passed on as a session variable but hasn't maintained its integrity as an object.:confused:

is it that session variables can't be objects?

mordred
04-03-2003, 06:08 PM
On your second page, before you instantiate the session in which you previously stored the object, you have to include the class definition for this class. If you stored it in a separate file like Quiz.class.php, it's a matter of adding a require_once before the call to session_start() is issued.
Otherwise the object can not be deserialized correctly and you end up with this error message.

Session variables can hold objects, and this is a major advantage for building object-oriented persistance layers in PHP webapps.

ASAAKI
04-04-2003, 09:36 AM
not working.
i can't require 'mcqclass.php' before session_start(); because then it says 'headers already sent'. so i required it after session_start.

i get the same error as i said before. and if i attempt to :


echo($mcq[0]->id);

then i also get this:
Parse error: parse error, expecting `T_OLD_FUNCTION' or `T_FUNCTION' or `T_VAR' or `'}'' in c:\phpdev\www\learning\mcqclass.php on line 57

but i use the mcq object without any problems, making new instances of it and using its methods, on the first page.
:confused:

mordred
04-04-2003, 11:15 AM
Look into your class file and see if somewhere output is echoed/printed to the browser. This is the cause of your "headers already sent" error. Your class file should only consist of valid php code within the <?php tags, watch for an eventual newline before or after these tags.

What I describes is the correct way to use objects in sessions and is also described in the manual. You can't just include the class file after starting the session, that will never work.

Your last error description seems to be caused by the previous errors, but it's hard to say without knowing the exact source code.

ASAAKI
04-04-2003, 02:41 PM
i don't exactly understand.
here's my source, 'mcqclass.php':


<?php
class MCQ{
var $id;
var $type;
var $mark;
var $question;
var $a;
var $b;
var $c;
var $d;
var $e;
var $ans;

function MCQ($id){
$this->id = $id;
$sql="SELECT `a`,`b`,`c`,`d`,`e`,`ans`,`type`,`mark`, `question` FROM `mcq` WHERE `id`='".$this->id."'";
$result=mysql_query($sql) or die("Sorry, unable to extract MCQ question.");
$row_array=mysql_fetch_row($result);
$this->a = $row_array[0];
$this->b = $row_array[1];
$this->c = $row_array[2];
$this->d = $row_array[3];
$this->e = $row_array[4];
$this->ans = $row_array[5];
$this->type = $row_array[6];
$this->mark = $row_array[7];
$this->question = $row_array[8];
}

function printQ($qno){
echo("[<span class='no'>".$qno."</span>] ".$this->question." </span><br>");
}


function printChoices($qno){
echo("A <input type='radio' value='a' name='m".$qno."' class='rdo'> &nbsp &nbsp &nbsp ".$this->a."<br>");
echo("B <input type='radio' value='b' name='m".$qno."' class='rdo'> &nbsp &nbsp &nbsp ".$this->b."<br>");
echo("C <input type='radio' value='c' name='m".$qno."' class='rdo'> &nbsp &nbsp &nbsp ".$this->c."<br>");
echo("D <input type='radio' value='d' name='m".$qno."' class='rdo'> &nbsp &nbsp &nbsp ".$this->d."<br>");
if($this->e){echo("E <input type='radio' class='rdo' value='e' name='m".$qno."'> &nbsp &nbsp &nbsp ".$this->e."<br><br>");}
}

/*
function saveProgress($userid,$s_ans){
if($s_ans){//if user has given any answer for this question then
// select from the db to check if he's already saved progress on this question before.
// if he has, we'll use an update query.
// if he hasn't we'll insert.
}
}
*/

function correctAns($s_ans){
$s_ans==$this->ans ? $this->result = 1 : $this->result = 0;
}
?>


i don't have any extra lines around the php tags...

this is the first time i'm doing OOP so i'm likely to be making some major mistakes...:o

mordred
04-04-2003, 02:54 PM
function correctAns($s_ans){
$s_ans==$this->ans ? $this->result = 1 : $this->result = 0;
}
} // <- this bracket is missing, your class is not "closed"
?>


There was the above error in your code excerpt and it lead to the last error you described. Try storing the object again with the fixed code and report if the other errors persist.

ASAAKI
04-05-2003, 01:28 PM
thanks. silly mistake:)

now all the errors have gone, except the "call to a member function on a non-object".
there is no error any more when i do:
echo($mcq[0]->id);
in fact there is nothing when i do that. i still don't get that mcq object's id.

but when i use a method of the object, like:
$result[$i]=$mcq[$i]->correctAns($s_ans[$i]);

then i get the above "non-object" error.

mordred
04-05-2003, 02:47 PM
How do you save your array of objects in the session? If you do it like



session_start();
$_SESSION['mcq'] = $mcq;


and retrieve it on the second page like



// class definition... see above
session_start();
$mcq = $_SESSION['mcq'];
echo $mcq[0]->question;


then the stored question attribute should be printed out. Observe that your correctAns() method is not returning anything, so nothing useful could be stored in the $result array.

In your first post, you do some strange scripting with eval() which purpose is not clear to me. If you can provide some more info how you a) store the object array and b) retrieve the object array from the session we should be able to narrow down the source of the error.

ASAAKI
04-05-2003, 08:28 PM
i added "return $result;" in the correctAns function, and i used the code you said. for some reason, it still isn't working.

Here's an explanation of the eval code, etc.

the site i'm working on has lessons, and exercises after each lesson.

depending on the lesson, there may be any number of MCQs. The 'mcq' table in the db has a field called 'lesson_id'. after the user decides to take the exercise of the lesson he's currently studying, the lesson_id that he chooses gets passed on to the exercises page, and is used as a parameter to extract all the IDs of the MCQs, 'WHERE mcq.lesson_id='.$lesson_id.
using that query i get all the IDs of the relevant MCQs that should be displayed. according to the number of rows fetched, i make the variable '$no_mcqs'.
then, according to the IDs i fetched, i use a loop to instantiate new MCQ objects, and pass these IDs one by one into the MCQ function to create a new MCQ object of the mcq[] array:



for($i=0;$i<$no_mcqs; $i++){
$j=$i+1; // this is just to get the printed question number to start from 1 instead of 0.
// the next two lines fetch the mcq IDs and then the id[] array gets these IDs
$row_array=mysql_fetch_array($result);
$id[$i]=$row_array[0];
// now create new MCQ objects, using the ID we just extracted.
// each object is part of the mcq[] array.
$mcq[$i]=new MCQ($id[$i]);
// print out the question and the choices of the current object, using the MCQ methods.
$mcq[$i]->printQ($j);
$mcq[$i]->printChoices($i);
}

then, at the bottom of the form i have a hidden input element that stores the number of MCQs in this exercise.
after answering the questions, the user hits 'Done' and the form gets submitted.
almost forgot, i do this to store the object array:


if(!session_is_registered($mcq)){
session_register($mcq);
$_SESSION['mcq']=$mcq;
}

actually, before i used a verbose loop to do that, a lot like what's mentioned below as the old code that i'm not using now.

hope everything's clear so far. this was all on mcq1.php.

on the next page, mcq2.php, i do this:


require("mcqclass.php");
session_start();
$no_mcqs=$_GET['no_mcqs'];
// the connection stuff....

/* now i'm using a loop (for the number of MCQs that there are),
to assign all the mcq objects in the SESSION's mcq array to the
mcq[] array on this page.
let's suppose the current value of $i in this loop is 1. so the eval
code will evaluate to:
$mcq[1] = $_SESSION['mcq[1]'];
this way all the objects in the SESSION's array should get into the mcq array of this page.
*/

for($i = 0; $i < $no_mcqs; $i++){
eval("\$mcq[".$i."] = \$_SESSION['mcq[".$i."]'];");
}


that's what i was doing, but now, as you said, i simply get the array like this rather than looping through every single member of the array:


$mcq=$_SESSION['mcq'];

then i try to:

echo($mcq[0]->id);
which apparently does nothing.

and when i try to:

$result=$mcq[0]->correctAns($s_ans[0]);
// the $s_ans[0] is the first answer submitted by the user, in the $s_ans array.

then i get the old error that says i'm calling a member function on a non-object.

:confused:
so what else do you suggest?

thanks.

mordred
04-05-2003, 08:43 PM
Have you tried



var_dump($_SESSION);


on the second page, and what does it report? Is there any data in the session at all?

Further, you should not use session_register if you do also use $_SESSION. session_register was the way to register a session variable if you have register_globals turned on, and that is now outdated since the advent of the super-global $_SESSION array. Just treat $_SESSION as a normal array; there's no need to explicitly register session variables anymore. That's of course only true if you're running a php version >= 4.1 and register_globals is turned off.
According to the manual, the use of both session registering approaches in one script can lead to unexpected and undeterminable behaviour - so better stick to one, in order to rule out the possiblity of this issue happening.

mordred
04-05-2003, 08:51 PM
Two more things I just noticed:

1. You use session_register incorrectly. This function expects strings of variable names instead of the variables themselves, see the manual. I would not be surprised if your session is totally empty on the second page.

2. Better use isset($_SESSION['mcq']) rather than session_is_registered for the same reason why you shouldn't use session_register at all.

Quoted from the manual:



If you are using $_SESSION (or $HTTP_SESSION_VARS), do not use session_register(), session_is_registered() and session_unregister().


http://www.php.net/manual/en/function.session-register.php

I know from my own experience that sessions can be a real PITA sometimes, but I'm optimistic that we solve your problems really soon. :)

ASAAKI
04-06-2003, 10:08 PM
okay here's the report:D

first let me tell you that the current lesson has 2 mcqs, so the array only has two objects.

when i added "var_dump($_SESSION);" on the second page, without changing anything else, i did get a couple of lines of something mentioning "array(2)" and "Object", sorry i didn't manage to catch that, and when i changed the code i couldn't revert to the old one. but from what i understood of it, the session was holding an array, that did seem to have objects, which might have understood that were supposed to carry something, but they were all empty. perhaps only the structure got maintained.

anyway, i changed the code then. got rid of session_is_registered, and just used $_SESSION directly. i got the same result, the lines i mentioned above.

then, as per an example in that phpnet link, i used this on mcq1.php:


/*old part -- just getting the mcq objects and stuff here */
$no_mcqs=mysql_num_rows($result);
for($i=0;$i<mysql_num_rowS($result);$i++){
$j=$i+1;
$row_array=mysql_fetch_array($result);
$id[$i]=$row_array[0];
$mcq[$i]=new MCQ($id[$i]);
$mcq[$i]->printQ($j);
$mcq[$i]->printChoices($i);
}
/*here's the changed part */
$mcqObjArray=serialize($mcq);
$_SESSION['mcqObjArray'] = $mcqObjArray;


that's it.

on mcq2.php i did this:


$mcqObjArray=unserialize($_SESSION['mcqObjArray']);


after which, (this is the good part!:)) i got this session output:

array(2) { ["mcq"]=> array(2) { [0]=> object(mcq)(10) { ["id"]=> string(3) "1.0" ["type"]=> string(8) "question" ["mark"]=> string(1) "1" ["question"]=> string(42) "Which of these answers is correct? (ans:C)" ["a"]=> string(16) "This is answer A" ["b"]=> string(16) "This is answer B" ["c"]=> string(16) "This is answer C" ["d"]=> string(16) "This is answer D" ["e"]=> string(16) "This is answer E" ["ans"]=> string(1) "C" } [1]=> object(mcq)(10) { ["id"]=> string(3) "2.0" ["type"]=> string(8) "question" ["mark"]=> string(1) "2" ["question"]=> string(42) "Which of these answers is correct? (ans:B)" ["a"]=> string(16) "This is answer A" ["b"]=> string(16) "This is answer B" ["c"]=> string(16) "This is answer C" ["d"]=> string(16) "This is answer D" ["e"]=> string(16) "This is answer E" ["ans"]=> string(1) "B" } } ["mcqObjArray"]=> string(658) "a:2:{i:0;O:3:"mcq":10:{s:2:"id";s:3:"1.0";s:4:"type";s:8:"question";s:4:"mark";s:1:"1";s:8:"question";s:42:"Which of these answers is correct? (ans:C)";s:1:"a";s:16:"This is answer A";s:1:"b";s:16:"This is answer B";s:1:"c";s:16:"This is answer C";s:1:"d";s:16:"This is answer D";s:1:"e";s:16:"This is answer E";s:3:"ans";s:1:"C";}i:1;O:3:"mcq":10:{s:2:"id";s:3:"2.0";s:4:"type";s:8:"question";s:4:"mark";s:1:"2";s:8:"question";s:42:"Which of these answers is correct? (ans:B)";s:1:"a";s:16:"This is answer A";s:1:"b";s:16:"This is answer B";s:1:"c";s:16:"This is answer C";s:1:"d";s:16:"This is answer D";s:1:"e";s:16:"This is answer E";s:3:"ans";s:1:"B";}}" }

which means that this time the session stored everything all right! thank you thank you mordred!:D:D

BUT, if i try to echo $mcq[0]->id i still get nothing, and if i try to use the correctAns function, i get the same old error:
Fatal error: Call to a member function on a non-object in c:\phpdev\www\learning\mcq2.php on line 75


:rolleyes:

ASAAKI
04-07-2003, 07:54 PM
oopsies, i'd been making this retarded mistake:

$result=$mcq[0]->correctAns($s_ans[0]);

instead of:

$result=$mcqObjArray[0]->correctAns($s_ans[0]);

:rolleyes:

it's all working now. thanks for all the help mordred! :D:)

mordred
04-07-2003, 09:39 PM
Glad you sorted it out yourself, I really began to wonder if this was one of the strange cases session handling sometimes throws up, and which are different depending on the exact PHP version. From what I see of your posted code, I'd say it *should* also work without explicitly (de-)serializing the array of objects into the session, because that's how I do it usually and so far it worked ok for me.

Care to tell us which PHP version you run exactly? Just so others might who experience the same symptoms can verify that your workaround does apply to them too. :)

ASAAKI
04-07-2003, 10:27 PM
well i tried it. it *did* work without unserializing.:)
i'm using PHP 4.2.3.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum