Klassenstruktur, API Klasse

Alles, was PHP betrifft, kann hier besprochen werden.

Klassenstruktur, API Klasse

Postby Thasmo » 25. December 2005 23:37

Folgendes funktioniert nicht:

Code: Select all
<?php

class GameServerAPI {
   public function __construct($game, $address) {
      return new Quake3Server($address);
   }
}

abstract class GameServer {
   public function __construct($address) {
   }
   
   public function getData() {
   }
   
   protected function setPort($port) {
   }
   
   protected function connect() {
   }
   
   protected function request($command) {
   }
}

class Quake3Server extends GameServer {
   public function __construct($address) {
      parent::__construct($address);
      parent::setPort();
      parent::connect();
      parent::request();
   }
}

$server = new GameServerAPI('quake3', '[IP]');
$server->getData();

?>


Hat jemand eine Lösung für mich, ich weiß nicht wie ich das hinbekomme ... Danke vielmals! =o)
Thasmo
 
Posts: 32
Joined: 28. November 2005 13:25

Postby nattl » 26. December 2005 10:01

hallo,

du instanzierst zuerst ein neues GameServerAPI Objekt und willst dann eine Referenz auf ein Quake3Server-Objekt reinklatschen... das kann nicht gehen ;). Entweder du merkst dir die Referenz auf Quake3Server in der Klasse GameServerAPI, dann mußt du aber eine Methode schreiben, die dieses Objekt zurückgibt und diese jedes mal beim Zugriff auf Quake3Server aufrufen (z.b. $server->getServer()->getData()), was zugegeben etwas umständlich ist.
Oder du rufst dein Objekt mithilfe eines Scope-resolution-operators auf, was IMHO eleganter ist:

Code: Select all
<?php

class GameServerAPI {
   public function getServer($game, $address) {
        return new Quake3Server($address);   
   }
}

abstract class GameServer {
   public function __construct($address) {
   }
   
   public function getData() {
   }
   
   protected function setPort($port) {
   }
   
   protected function connect() {
   }
   
   protected function request($command) {
   }
}

class Quake3Server extends GameServer {
   public function __construct($address) {
      parent::__construct($address);
      parent::setPort();
      parent::connect();
      parent::request();
   }
}

$server = GameServerAPI::getServer('quake3', '[IP]');
$server->getData();

?>


So wie du GameServer bis jetzt implementiert hast, hättest du auch ein Interface draus machen können, ich schätze aber mal, dass da noch was kommt :wink:

lg,
Natascha
User avatar
nattl
 
Posts: 22
Joined: 26. October 2005 07:50
Location: Vienna

Postby Thasmo » 26. December 2005 14:37

Hm. Deine Variante macht doch absolut genau dasselbe wie meine, oder nicht? *grübel*
Thasmo
 
Posts: 32
Joined: 28. November 2005 13:25

Postby Thasmo » 26. December 2005 14:51

Problem 1:
http://community.apachefriends.org/f/viewtopic.php?t=15112

Problem 2:
Die Klasse funtioniert nicht.

Code: Select all
<?php

class GameServerAPI {
   private $game, $address;
   
   public function initiate($game, $address) {
      $this->game = strtolower($game);
      $this->address = $address;
      
      switch($this->game) {
         case 'q3':
         case 'q3a':
            return new Quake3Server($this->address);
            break;
         
         default:
            return;
            break;
      }
   }
}

abstract class GameServer {
   protected $ip, $port, $data, $status, $conn;
   
   public function __construct($address, $timeout = 1) {
      $this->timeout = $timeout;
      
      if(preg_match('/:/', $address))
         list($this->ip, $this->port) = split(':', $address);
      else
         $this->ip = $address;
   }
   
   public function __destruct() {
      fclose($this->conn);
   }
   
   public function getPort() {
      return $this->port;
   }
   
   public function getIp() {
      return $this->ip;
   }
   
   public function getData() {
      return $this->data;
   }
   
   protected function setPort($port) {
      $this->port = empty($this->port) ? $port : $this->port;
   }
   
   protected function connect() {
      if(!$this->conn = fsockopen('udp://' . $this->ip, $this->port, $errno, $errstr))
         $this->printLine('<b>ERROR:</b> Connection timed out or server is offline.');
   }
   
   protected function request($command) {
      if($this->conn) {
         fwrite($this->conn, $command);
         
         stream_set_timeout($this->conn, $this->timeout);
         stream_set_blocking($this->conn , true);
         
         $this->data = fgetc($this->conn);
         
         $meta = stream_get_meta_data($this->conn);
         
         if($meta['timed_out'])
            $this->printLine('<b>ERROR:</b> Server timed out.');
         else {
            if($meta['unread_bytes'] > 0)
               $this->data .= fread($this->conn, $meta['unread_bytes']);
            else
               $this->printLine('<b>ERROR:</b> No(?) data available.');
         }
      }
      else
         $this->printLine('<b>ERROR:</b> Cannot establish connection.');
   }
   
   protected function printLine($line) {
      trigger_error($line);
   }
}

class Quake3Server extends GameServer {
   const PORT = '27960';
   const COMMAND = "\xFF\xFF\xFF\xFFgetStatus\x00";
   
   public function __construct($address) {
      parent::__construct($address);
      parent::setPort(self::PORT);
      parent::connect();
      parent::request(self::COMMAND);
   }
}

$s1 = GameServerAPI::initiate('q3', '82.192.78.42:29060');
print $s1->getIp() . ':' . $s1->getPort() . '<br />';
print $s1->getData();

?>


Leider bekomme ich keine Fehlermeldungen, daher weiß ich auch nicht was los ist. =o(

PS: Problem 1 nervt wahnsinnig!!
Thasmo
 
Posts: 32
Joined: 28. November 2005 13:25

Postby Thasmo » 26. December 2005 23:29

nattl wrote:hallo,

du instanzierst zuerst ein neues GameServerAPI Objekt und willst dann eine Referenz auf ein Quake3Server-Objekt reinklatschen... das kann nicht gehen ;). Entweder du merkst dir die Referenz auf Quake3Server in der Klasse GameServerAPI, dann mußt du aber eine Methode schreiben, die dieses Objekt zurückgibt und diese jedes mal beim Zugriff auf Quake3Server aufrufen (z.b. $server->getServer()->getData()), was zugegeben etwas umständlich ist.
Oder du rufst dein Objekt mithilfe eines Scope-resolution-operators auf, was IMHO eleganter ist:

<CODE>

So wie du GameServer bis jetzt implementiert hast, hättest du auch ein Interface draus machen können, ich schätze aber mal, dass da noch was kommt :wink:

lg,
Natascha


Also, ich habe das jetzt versucht aber anscheinend functioniert das auch nicht so wie du es mir vorgeschlagen hast.

Hm. :o(
Thasmo
 
Posts: 32
Joined: 28. November 2005 13:25

Postby nattl » 31. December 2005 09:32

hallo,

wie soll das gehen

Code: Select all
class GameServerAPI {
   private $game;
   private $address;
   
   public function initiate($game, $address) {
      $this->game = strtolower($game);
      $this->address = $address;
[...]


wenn du die Klasse weiter unten so

Code: Select all
$s1 = GameServerAPI::initiate('q3', '82.192.78.42:29060');


aufrufst?

$this ist ein Rückbezug eines Objekts auf seine eigene Referenz. Dadurch, dass du mit :: aufrufst, gibts aber keine Instanz, ergo keine Referenz auf sich selbst.

Mein Codebspiel funktioniert bei mir (habs auch debugged).

Vielleicht solltest du dein Problem genauer beschreiben. Anhand des Codes weiß ich, was die Klassen machen sollen, allerdings weiß ich nicht, was *du* dir erwartest zu sehen.. :wink:
User avatar
nattl
 
Posts: 22
Joined: 26. October 2005 07:50
Location: Vienna

Postby Thasmo » 04. January 2006 13:15

Ich versuche eine Klassenstruktur in PHP5 (Bin da etwas neu, in PHP5 und OOP) zu erstellen mit der ich durch eine "Handler" Klasse, "API" Klasse mehrere Unterklassen zu verwenden/steuern.

Zum Beispiel eine Datenbank Klassenstruktur mit der ich verschiedene Datenbanken abfragen kann ohne deren genauen Befehl kennen zu müssen.

Sprich:

class DatabaseAPI
abstract class Database
class MySql extends Database
class MsSql extends Database
etc.

Dann möchte ich die API Klasse
ungefähr so aufrufen:

Code: Select all
$db = new DatabaseAPI('mysql');


Und dann möchte ich die Methoden in der Klasse MySql
ansprechen können, und in Falle von

Code: Select all
$db = new DatabaseAPI('mssql');


eben die Methoden der Klasse MsSql.

Ich suche so gesagt eine Möglichkeit eben durch die API
Klasse alle anderen "verwandten" Klassen zu steuern.
Thasmo
 
Posts: 32
Joined: 28. November 2005 13:25

Postby KingCrunch » 04. January 2006 15:35

Schau dich mal um zum Thema "Design Pattern"/"Entwurfsmuster" und speziell "Factory"
Nicht jeder Fehler ist ein Bug ...
KingCrunch
 
Posts: 1724
Joined: 26. November 2005 19:25

Postby nattl » 06. January 2006 12:45

design patterns kann ich auch nur raten ;)

wenns nur um einen abstraktionslayer für datenbanken ginge, könnt ich dir creole ans herz legen.
User avatar
nattl
 
Posts: 22
Joined: 26. October 2005 07:50
Location: Vienna


Return to PHP

Who is online

Users browsing this forum: No registered users and 60 guests