[PHP] Access tot object variabelen debuggen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Toiletman
  • Registratie: Februari 2000
  • Laatst online: 17-09 14:14
Net als een aantal anderen ben ik bezig met het maken van een botje voor de GoTBotContest. Voor degenen die niet op de hoogte zijn: er draaien servers waarop bots kunnen connecten en middels verschillende commando's elkaar kunnen beschieten. Ik programmeer m'n bot in PHP en heb em object georienteerd gemaakt. In dit geval betekent het dat de Bot een Brein en een Parser object bezit. De Bot houdt z'n eigen status bij: hoe lang hij al leeft, hoeveel energie er in z'n batterij zit en in welke beurt hij nu zit, verder kan de bot commando's versturen naar de server en houdt hij de logs bij.
De Parser leest de berichten die van de server binnenkomen en roept op basis daarvan functies in het brein aan, of update waarden in de bot. Het brein ten slotte reageert op berichten die binnenkomen van de server, neemt beslissingen en instrueert de bot welke commando's te versturen naar de server.
Het probleem zit hem in het opslaan van de gegevens die in de Parser binnenkomen in de bot. Beide opbjecten kennen elkaar: eerst wordt het brein aangemaakt, dan de bot, die een reference van dat brein binnenkrijgt en zelf een nieuwe Parser maakt. Daarna wordt het brein wordt opgestart met een reference naar de bot; het testscript ziet er dan als volgt uit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
$hermanBrein = new GotBotBrains;
$herman = new ToiletBot("Quitter","herman",& $hermanBrein);
$hermanBrein->startup(& $herman);
if(!$herman->startConnections()){
    // doe niets
}
else if(!$herman->startBot()){
    // doe niets
}
else if(!$herman->runBot()){
    // doe niets
}
echo "klaar!";


Nog wat meer stukjes interessante code:

Variabelen en constructor van ToiletBot:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Eigen variabelen/objecten
/***************************/
var $displev;
var $name;
var $pass;
var $fp; //verbinding naar de server
var $ears; // eigen object dat de stream uitleest en afhankelijk van de daar gekregen info messages dispatched naar Brains
var $battery;
//var $mySQLDB; // eigen object dat de verbinding met de mySQLDB onderhoudt en waar dus ook alle mysql functies zijn ondergebracht
var $brains; // eigen object dat de beslissingen neemt, z'n eigen geheugen beheert en de waarden van het object vaststelt
var $startTime; // tijd waarop het script aangeroepen wordt
var $receivedTurnTime; // tijd waarop het script nieuwe turns binnenkrijgt (en het spel dus eigenlijk is begonnen)
var $sentTurnTime; // tijd waarop een beurt aan deze kant is doorlopen
var $endOfLoopTime; // tijd waarop het script totaal klaar is met zijn beurt (inclusief wegschrijven naar DB enzo)
var $lifeTime; // levenstijd van de bot (in turns)
var $turnID;
var $out; //outputbuffer
var $quit;

// logs
var $comLog; // logt de communicatie & timestamps.
var $brainLog; // geeft AI-gegevens weer.
// Stap 0
// Constructor
function Toiletbot($name,$pass="onzin", & $brains){
    $this->displev=MSGTYPE_STATUS+MSGTYPE_ERROR+MSGTYPE_AI+MSGTYPE_INC+MSGTYPE_OUT;//+MSGTYPE_DEBUG;
    $this->log("In Toiletbot Constructor",MSGTYPE_DEBUG);
    $this->startTime=microtime_float();
    //$this->mySQLDB=new MySQLDB; // CONSTRUCTOR MOET NOG GEMAAKT
    $this->name=$name; //WAAROM IS NAME ROOD??? geen idee, stomme highlighting?!
    $this->pass=$pass;
    $this->ears=new GotBotParser($this);
    $this->brains=& $brains;
    $this->lifeTime=0;
    $this->turnID=0;
    $this->battery=0;
    $this->out="";
    $this->quit=false;      
    $this->log("I was born at $this->startTime",MSGTYPE_STATUS);
}
/**** [SNIP]****/

Dan hetzelfde voor GotBotParser:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var $fp;
var $bot;
var $newcommand;
var $input;
var $receiveTime;
var $expectScanRes;
var $expectFireRes;
var $numMessages;
var $newCommand;

function GotBotParser(&$bot){
    $this->bot=&$bot;
    $this->bot->log("In GotBotParser Constructor",MSGTYPE_DEBUG);
    $this->fp=&$bot->fp;
    $this->input="";
    $this->expectScanRes=false;
    $this->expectFireRes=false;
    $this->numMessages=0;
    $this->newCommand=false;
}
/**** [SNIP]****/

Welnu, op naar de code waar het fout gaat:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function processTURN(&$errstr, & $lifeTime){
    $this->bot->log("In GotBotParser processTURN(), myBot: ".$this->bot->name,MSGTYPE_DEBUG);
    $startOfTurn=true;
    do{
    if(!$this->isERROR())
    {
        // isERROR() heeft hier net een nieuwe regel opgehaald
        if($startOfTurn && strpos($this->input, "NEWTURN")===0 ){
            $this->bot->log("In GotBotParser processTURN(): NEWTURN",MSGTYPE_DEBUG);
            $this->newCommand=false;
            $tempArray=split(' ',$this->input);
            $this->bot->turnID=$tempArray[1];
            $this->bot->log("#### turnID: $tempArray[1], in de bot: ".$this->bot->turnID." ### ",MSGTYPE_STATUS);
            $this->numMessages=$tempArray[2];
            $this->bot->battery=$tempArray[3];
            $this->bot->log("#### battery: $tempArray[3], in de bot: ".$this->bot->battery." ### ",MSGTYPE_STATUS);
            //$lifeTime=$lifeTime+1; dit werkt wel als & $lifeTime als parameter wordt meegegeven
            $this->bot->updateLifeTime(); // dit werkt niet... zo ontzettend vaag! Als hij van binnenin de bot wordt aangeroepen doet hij het wel...
            $this->bot->log("### lifeTime: ".$this->bot->lifeTime." ### ",MSGTYPE_STATUS);
            $startOfTurn=false;
            continue; // het aantal nog te komen berichten is vastgelegd, we komen hier nu niet meer terug, meteen door naar de conditie
        }
/**** [SNIP] ****/

Let op de uitgecommente probeersels, daar kom ik later nog even op terug

Dit levert de volgende output op:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DEBUG 1123109601.04 : In GotBotParser processTURN(), myBot: Quitter
DEBUG 1123109601.04 : In GotBotParser isERROR()
DEBUG 1123109601.04 : In GotBotParser getCommand()
DEBUG 1123109601.04 : In GotBotParser getCommand(), streamlees gedeelte
DEBUG 1123109601.04 : In GotBotParser getCommand(): start do-while-loop
DEBUG 1123109603.04 : In GotBotParser getCommand(): na fgets: NEWTURN 22950 0 100 
DEBUG 1123109603.04 : In GotBotParser getCommand(): na do-while-loop: NEWTURN 22950 0 100 
SERVER <<< 1123109603.04 NEWTURN 22950 0 100 
DEBUG 1123109603.04 : In GotBotParser isERROR(), returning false
DEBUG 1123109603.04 : In GotBotParser processTURN(): NEWTURN
STATUS: #### turnID: 22950, in de bot: 22950 ### 
STATUS: #### battery: 100 , in de bot: 100 ### 
DEBUG 1123109603.04 : in Toiletbot updateLifeTime(), lifeTime: 7
STATUS: ### lifeTime: 8 ### 
DEBUG 1123109603.04 : In GotBotParser processTURN(): einde functie

Dat ziet er prima uit toch, wat is er dan mis... nou als we gaan kijken in de bot zelf:
PHP:
1
2
3
4
5
6
7
8
9
10
11
function runBot(){
    $this->log("In Toiletbot runBot",MSGTYPE_DEBUG);
    while(!feof($this->fp)&&!$this->quit){
        //$this->updateLifeTime(); dit werkt wel
        $this->log("In GotBotParser runBot(), binnen main loop",MSGTYPE_DEBUG);
        $this->log("Lifetime: ".$this->lifeTime.", Battery: ".$this->battery.", turnID: ".$this->turnID,MSGTYPE_STATUS);
        if(!$this->ears->processTURN($errstr,& $this->lifeTime)){
            $this->log("There's something wrong with the NEWTURN: $errstr",MSGTYPE_ERROR);
            return false;
        }
/**** [SNIP ****/

Dan zou je denken dat het statusstukje nu zou moeten weergeven dat de batterij vol, is we in turn 22950 zitten en dat m'n lifeTime 7 is.
Echter:
code:
1
2
3
4
5
DEBUG 1123109603.04 : In ToiletBot runBot, hierna zou brains aan de slag moeten
DEBUG 1123109603.04 : In GotBotBrains work(), myBot: Quitter
DEBUG 1123109603.04 : In Toiletbot flushOut()
DEBUG 1123109603.04 : In GotBotParser runBot(), binnen main loop
STATUS: Lifetime: 0, Battery: 0, turnID: 0

0... hoe kan dat nou? We hadden die variabelen toch net veranderd? Om de lifetime te updaten gebruiken we zelfs een functie binnen de bot zelf, die ons eerder nog vertelde dat de lifeTime toch echt 7 is....
Dit is de functie:
PHP:
1
2
3
4
function updateLifeTime(){
    $this->log("in Toiletbot updateLifeTime(), lifeTime: ".$this->lifeTime,MSGTYPE_DEBUG);
    $this->lifeTime++;
}

Als ik de functie updateLifeTime() iedere loop aanroep vanuit de bot zelf, gaat het wel goed, dan gaat de lifeTime teller wel lopen. Het is toch compleet belachelijk dat hij het dus niet doet als de functie wordt aangeroepen vanuit een ander object?
Verder heb ik geprobeerd om hem te veranderen als ik hem als reference meegeef aan het processTurn commando van GotBotParser, ook dit werkt.
Ten slotte heb ik nog een testscript gemaakt waarin ik dezelfde situatie namaak in een simpele setting (2 classes en wat simpele functies) ook daar werkt het allemaal gewoon.
Ik heb dagen naar mijn code zitten staren om uit te vissen wat er nou mis is, maar ik zie geen rare dingen in m'n code. Mijn vraag is dus: zien jullie die wel, of doet PHP gewoon ontzettend vaag :?.
Ik heb de code maar geupload, zodat mensen niet afhankelijk zijn van de hier geposte snippets:
testscript en de complete code van de bot(excuse the filename).

Only dead fish go with the flow


Acties:
  • 0 Henk 'm!

  • aex351
  • Registratie: Juni 2005
  • Laatst online: 02:04

aex351

I am the one

offtopic Wat mij altijd opvalt, waarom moet altijd alles in het engels.

[ Voor 15% gewijzigd door aex351 op 04-08-2005 02:26 ]

< dit stukje webruimte is te huur >


Acties:
  • 0 Henk 'm!

  • Genoil
  • Registratie: Maart 2000
  • Laatst online: 12-11-2023
Ziet er uit als een typisch PHP4 pass-by-copy probleem waar het pass-by-reference zou moeten zijn. Als niemand anders het doet doe ik zo ff een voorbeeldje...

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<pre><?
class a {
    var $attrib;
    
    function a () {
        $this->attrib = 'value1';
    }

       function setAttrib($var) {
        $this->attrib = $var;
    }
    
    function getAttrib() {
        return $this->attrib;
    }
}

class b {
    var $objA;

    function b () {
        $this->objA = & $objA;
    }

    function setAByCopy($objA) {
        $this->objA = $objA;
    }
    
    function setAByRef(& $objA) {
        $this->objA = & $objA;
    }
    
    function getAttrib() {
        return $this->objA->getattrib();
    }


}

$objA = & new a();

$objB1 = & new b();
$objB2 = & new b();

$objB1->setAByCopy($objA);
$objB2->setAByRef($objA);

$objA->setAttrib('value2');  //verander attrib

echo $objB1->getAttrib();   //geeft 'value1'
echo "\n";
echo $objB2->getAttrib();   //geeft 'value2'
?></pre>


(Noot: In PHP5 worden objecten by-default by reference gepassed, dus krijg je 2 keer 'value2')

[ Voor 96% gewijzigd door Genoil op 04-08-2005 09:28 ]


Acties:
  • 0 Henk 'm!

  • Toiletman
  • Registratie: Februari 2000
  • Laatst online: 17-09 14:14
Genoil schreef op donderdag 04 augustus 2005 @ 09:02:
Ziet er uit als een typisch PHP4 pass-by-copy probleem waar het pass-by-reference zou moeten zijn. Als niemand anders het doet doe ik zo ff een voorbeeldje...
PHP:
1
2
3
4
5
6
[*SNIP*]
$objA = & new a(); 

$objB1 = & new b(); 
$objB2 = & new b(); 
[*SNIP*]

(Noot: In PHP5 worden objecten by-default by reference gepassed, dus krijg je 2 keer 'value2')
Mijn testscript ziet er precies zo uit als dat van jou, maar ik heb toch maar wat zitten klooien: ik gaf zelf als functieargument al het adres van de variabele (& $var) mee in de functieaanroep, dat moest gewoon de variabele zelf zijn, dus het probleem is nu opgelost! :), bedankt! Daarnaast dacht ik dat new automatisch een reference teruggeeft, maar dat blijkt ook niet zo te zijn.

[ Voor 13% gewijzigd door Toiletman op 04-08-2005 12:26 ]

Only dead fish go with the flow


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
aex351 schreef op donderdag 04 augustus 2005 @ 02:26:
offtopic Wat mij altijd opvalt, waarom moet altijd alles in het engels.
Omdat de taal zelf en de lib functies ed. ook allemaal in het engels zijn?

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • JeRa
  • Registratie: Juni 2003
  • Laatst online: 30-04 10:28

JeRa

Authentic

aex351 schreef op donderdag 04 augustus 2005 @ 02:26:
offtopic Wat mij altijd opvalt, waarom moet altijd alles in het engels.
Sinds ik een aantal jaar geleden erachter was gekomen dat Engelse documentatie vaak vele malen duidelijker is dan de (vertaalde) Nederlandse documentatie, ben ik ook alleen maar comments en output in het Engels gaan schrijven mits niet anders nodig was. Verder lijkt het me een kwestie van smaak :)

ifconfig eth0 down


Acties:
  • 0 Henk 'm!

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 01:32

alienfruit

the alien you never expected

Als je je brouwsel wil verkopen aan een buitenlander, hoef je je documentatie niet te vertalen ;)
Pagina: 1