Jump to content

Really confused..


Michdd

Recommended Posts

I have a class that has these variables:

 

public $socket, $id, $x, $y, $direction;

 

Within another class I'm looping through an array of those classes.. And I'm getting this error(sometimes):

 

Notice: Undefined property: stdClass::$socket

 

Which makes no sense because I'm not creating any stdClass instances.. So I used print_r to see what this was and I get this:

 

stdClass Object
(
    [x] => 2
    [y] => 1
    [direction] => 3
)

 

That's strange because it's almost the same as my Character class, except it's missing the socket and id properties. Also, just a note, both the socket and the id are set in the character class within the constructor.

 

Anyone have any idea why this could be happening?

Link to comment
Share on other sites

You'll get a stdClass object if you simply start using a variable as an object. eg;

 

$a->foo = 'bar';
$a->bob = 'blah';
print_r($a);

 

Obviously your not instantiating your class properly or something. We need to see some relevant code.

Link to comment
Share on other sites

That's strange, because it only happens sometimes.. Here's the relevant code:

 

Creating the object.

case PACKET_GETCHARID:
				$character = new Character($client, count($this->characters));
				$this->characters[] = $character;

 

Character class is really simple:

 

class Character
{
public $socket, $id, $x, $y, $direction;

public function __construct($s, $id)
{
	$this->socket = $s;
	$this->id = $id;
	echo "Character created! ({$this->socket}, {$this->id})\n";
}
}

Link to comment
Share on other sites

this line

$this->characters[] = $character;

 

you only use the this symbol inside the class itself. when you want to call a method of a class you instantiated inside a variable, you use the variable name

 

$character->characters[] = $character;

 

should help you out

I am using it it inside it's class.. The character class doesn't have an array of other characters (How would that make any sense?) $characters is a property of the server class, which is what it's in.

 

Even if that was the issue, it wouldn't work only sometimes.

Link to comment
Share on other sites

if you are

 

 

Creating the object.

case PACKET_GETCHARID:
				$character = new Character($client, count($this->characters));
				$this->characters[] = $character;

 

Character class is really simple:

 

class Character
{
public $socket, $id, $x, $y, $direction;

public function __construct($s, $id)
{
	$this->socket = $s;
	$this->id = $id;
	echo "Character created! ({$this->socket}, {$this->id})\n";
}
}

 

I thought when you said Creating Object, you meant that you were instantiating the object outside of the class. not to mention that I don't see any characters attribute in your character class itself. and if that is inside the character class, than why does the class instantiate objects of itself and store them in a seemingly non-existant class variable?

 

sorry if I misread what you posted, but the little that was posted didn't make much sense in the context it was in. perhaps post what is above or below the Object creation code you posted so I can get a better idea of why you are why that particular snippet is there.

Link to comment
Share on other sites

The first snippet I posted (creating the object and putting it in $this->characters) is within my Server class. The second snippet is just the Character class.

 

Are there any other places within your Server class where you instantiate and store Characters?  Also, can you show us the loop that's giving the error?

Link to comment
Share on other sites

Nope, that's the only place where characters are instantiated and stored in $characters.

 

I seem to be getting the error in different places; where ever I try to access the $id or $socket properties of the class. One place specifically is this:

 

private function getCharacterIndex($client)
{
	foreach($this->characters as $index => $character)
	{
		if($character->socket == $client)
		{
			return $index;
			break;
		}
	}
}

Link to comment
Share on other sites

I'm wondering if your data members are being overwritten somewhere, as nothing in your syntax jumps out at me.

 

Try this: make your character data members private and give them appropriate accessor methods.  For example -

 

class Character
{
   private $socket, $id, $x, $y, $direction;

   public function __construct($s, $id)
   {
      $this->socket = $s;
      $this->id = $id;
   }

   public function getSocket()
   {
      if ($this->socket) { return $this->socket; }
      else { return null; }
   }

   public function setSocket($s) //just in case you need to reset/change it
   {
      $this->socket = $s;
   }

   //etc for the rest of the data members
}

 

It's a bit of a hassle, but it ensures that your objects are properly encapsulated.  You may have a conditional or something else in your system that's trying to assign to the socket data member rather than check for its value (in other words, a missing or extraneous '=' somewhere).

Link to comment
Share on other sites

That's a really good idea, that I could be using '=' in a conditional by accident. However I don't think your idea is necessary. Only currently the source of this is quite small, under 200 lines in total. I searched everything and double checked for those errors, found nothing. Additionally, it seems like more than a coincidence that the two variables being set in the constructor are the two that are sometimes not being found.

Link to comment
Share on other sites

I just thought this could possibly help figure out the problem.. It's the only other place where $characters is messed with.. I still don't see how there could be a problem.. but who knows.

 

	private function disconnected($client)
{
	$index = array_search($client, $this->clients);
	$char_index = $this->getCharacterIndex($client);
	socket_close($this->clients[$index]);
	unset($this->clients[$index]);
	unset($this->characters[$char_index]);
	$this->characters = array_merge($this->characters);
	$this->sendMessageToAll(PACKET_REMOVE_CHARACTER . " " . $char_index);
	echo "A client disconnected\n";
}

Link to comment
Share on other sites

Here's my entire Server class source:

 

class Server
{	
public public $port = 5445, $address = '192.168.1.201';

private $clients, $master, $characters;

public function __construct()
{

	if (($this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
		echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
	socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
	if (($ret = socket_bind($this->master, $this->address, $this->port)) < 0)
		echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
	if (($ret = socket_listen($this->master, 5)) < 0)
		echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";

	$this->clients = Array($this->master);
	$this->run();
}

private function run()
{
	while(true)
	{
		$changed_sockets = $this->clients;
		$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);

		foreach($changed_sockets as $client)
		{
			if($client == $this->master)
			{
				$this->acceptNewClient();
			}
			else
			{
				$this->readMessageFromClient($client);
			}
		}
	}
}

private function acceptNewClient()
{
	if(($client = socket_accept($this->master)) < 0)
	{
		echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
		return;		
	}
	else
	{
		socket_write($client, '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . chr(0x00));
		$this->clients[] = $client;
		socket_getpeername($client, $client_ip);
		echo "Client successfully connected from " . $client_ip . "\n";
	}
}

private function sendMessageToClient($client, $packet)
{
	socket_write($client, $packet);
}

private function sendMessageToAll($packet)
{
	foreach($this->clients as $client)
	{
		if($client == $this->master)
			continue;
		socket_write($client, $packet);
	}
}

private function sendMessageToAllLimited($sender, $packet)
{
	foreach($this->clients as $client)
	{
		if($client == $this->master || $client == $sender)
			continue;
		socket_write($client, $packet);
	}
}

private function readMessageFromClient($client)
{
	$buffer = socket_read($client, 2048);
	if(!$buffer)
		$this->disconnected($client);
	else
	{
		if(trim($buffer) == '<policy-file-request/>')
			return;
		$packet = explode(' ', $buffer, 2);
		switch($packet[0])
		{
			case PACKET_CHAT:
				$this->sendMessageToAll(PACKET_CHAT . " $client wrote: {$packet[1]}");
			break;
			case PACKET_GETCHARID:
				$character = new Character($client, count($this->characters));
				$this->characters[] = $character;
				$this->sendMessageToClient($client, PACKET_GETCHARID . " " . $character->id);
			break;
			case PACKET_WALK:
				$data = explode(',', $packet[1]);
				$this->characters[$data[0]]->x = $data[1];
				$this->characters[$data[0]]->y = $data[2];
				$this->characters[$data[0]]->direction = $data[3];
				echo "$client : ({$this->characters[$data[0]]->x}, {$this->characters[$data[0]]->y})\n";
				$this->sendMessageToAllLimited($client, PACKET_WALK . " " . $this->characters[$data[0]]->id . "," . $this->characters[$data[0]]->x . "," . $this->characters[$data[0]]->y);
			break;
			default:
			break;
		}
	}
}

private function disconnected($client)
{
	$index = array_search($client, $this->clients);
	$char_index = $this->getCharacterIndex($client);
	socket_close($this->clients[$index]);
	unset($this->clients[$index]);
	unset($this->characters[$char_index]);
	$this->characters = array_merge($this->characters);
	$this->sendMessageToAll(PACKET_REMOVE_CHARACTER . " " . $char_index);
	echo "A client disconnected\n";
}

private function getCharacterIndex($client)
{
	foreach($this->characters as $index => $character)
	{
		if($character->socket == $client)
		{
			return $index;
			break;
		}
	}
}
}

Link to comment
Share on other sites

Your best bet is to:

 

1. Do what I suggested before.  I'm a big stickler for keeping data members private specifically for this reason.  Named accessor methods make it easier to see where/how an object's data members are being used, and keeping them private protects them from stray overwrites.

 

2. Write some error handling code.  Ensure that a Character exists.  Ensure that the proper data members have values before accessing them.  Code defensively.

 

3. Write debugging output.  At each major step of the process, output the appropriate info.

 

That all written, I think I may have just spotted your problem: it looks like your PACKET_WALK case is being invoked before you actually create a character.  That explains why those secondary data members are filled, but not the ones you usually set in the constructor.  $character becomes a default object at that point.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.