通过附加的信息在SplObjectStorage中查找对象


Find object in SplObjectStorage by attached info

我使用PHP Ratchet构建了一个聊天应用程序。

我将所有连接存储在SplObjectStorage中。

每个连接都将有用户id,我将通过以下方式将其附加:

   public function __construct() {
        $this->clients = new 'SplObjectStorage;
    }
   public function onOpen(ConnectionInterface $conn)
    {
        // Store the new connection to send messages to later
        $querystring = $conn->WebSocket->request->getQuery();
        foreach ($querystring as $value)
        {
            if($key == "senderId")
                $senderId = $value;
        } 
        $this->clients->attach($conn, $senderId);
        echo "New connection! ({$conn->resourceId}) senderId({$senderId})'n";
    }

当消息到达时,我希望以最快的方式获取与特定用户id相关的$conn对象。我可以像这样使用琐碎的foreach:

public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "'n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
     foreach ($this->clients as $client)
     {
                if ($from->getInfo() !== $client->getInfo()) {
                   // do stuff
                }
    }

我想知道是否有更快的方法。也许使用这样的功能:

$conn = $this->clients->getClientWithInfo("WANTED-INFO");

想要的方法是在我的所有连接上取消循环,以便向特定用户发送消息。我想获得与用户id相关联的连接。

在我看来,只有一种解决方案可以让它发挥作用,就像您期望的=>扩展SplObjectStorage类一样。但你有两个选择。

首先,您可以懒惰,并将getClientWithInfo方法添加到为您查找对象的类中:

class ConnectionStorageSimple extends SplObjectStorage
{
    public function getClientWithInfo($info)
    {
        $this->rewind();
        while ($this->valid()) {
            $object = $this->current(); // similar to current($s)
            $data = $this->getInfo();
            if ($info === $data) {
                $this->rewind();
                return $object;
            }
            $this->next();
        }
        return null;
    }
}
$conStorage = new ConnectionStorageSimple();
$con1 = new 'stdClass();
$con1->id = 1;
$con2 = new 'stdClass();
$con2->id = 2;

$conStorage->attach($con1, 1);
$conStorage->attach($con2, 2);
var_dump($conStorage->getClientWithInfo(1));
var_dump($conStorage->getClientWithInfo(2));
/**
 This will output something like that:
 class stdClass#2 (1) {
   public $id =>
   int(1)
 }
 class stdClass#3 (1) {
   public $id =>
   int(2)
 }
*/

另一种选择是,基于父函数构建one-info对象映射。这有点复杂:

<?php
class ConnectionStorage extends SplObjectStorage
{
    private $objInfoMapping = array();
    public function attach($object, $data = null)
    {
        if (null !== $data) {
            $this->objInfoMapping[$data] = $object;
        }
        parent::attach($object, $data);
    }
    public function detach($object)
    {
        $this->detach($object);
        parent::detach($object);
    }
    public function addAll($storage)
    {
        $this->addStorage($storage);
        parent::addAll($storage);
    }
    public function removeAll($storage)
    {
        $this->objInfoMapping = array();
        parent::removeAll($storage);
    }
    public function removeAllExcept($storage)
    {
        $this->objInfoMapping = array();
        $this->addStorage($storage);
        parent::removeAllExcept($storage);
    }
    public function unserialize($serialized)
    {
        parent::unserialize($serialized);
        $this->addStorage($this);
    }
    public function offsetUnset($object)
    {
        $this->detach($object);
        parent::offsetUnset($object);
    }
    protected function detachObject($obj)
    {
        $info = $this[$obj];
        if (array_key_exists($info, $this->objInfoMapping)) {
            unset($this->objInfoMapping[$info]);
        }
    }
    protected function addStorage(SplObjectStorage $storage)
    {
        $storage->rewind();
        while ($storage->valid()) {
            $object = $storage->current(); // similar to current($s)
            $data = $storage->getInfo();
            $this->objInfoMapping[$data] = $object;
            $storage->next();
        }
    }
    public function getClientWithInfo($info)
    {
        if (array_key_exists($info, $this->objInfoMapping)) {
            return $this->objInfoMapping[$info];
        }
    }
}
$conStorage = new ConnectionStorage();
$con1 = new 'stdClass();
$con1->id = 1;
$con2 = new 'stdClass();
$con2->id = 2;

$conStorage->attach($con1, 1);
$conStorage->attach($con2, 2);
var_dump($conStorage->getClientWithInfo(1));
var_dump($conStorage->getClientWithInfo(2));
/**
 This will also output something like that:
 class stdClass#2 (1) {
   public $id =>
   int(1)
 }
 class stdClass#3 (1) {
   public $id =>
   int(2)
 }
*/

这两个类之间的主要区别在于,第二个示例在大型数据集上的性能会更好,因为您不必迭代存储的所有对象。因为您只存储对自己数组的对象引用,所以额外的内存消耗不应该太大。

免责声明:这些课程只是为了说明各种可能性。第一个应该保存使用,但第二个应该测试更多

希望这能有所帮助。

这就是我所做的,看到它更简单快捷。

namespace mine;
use Ratchet'MessageComponentInterface;
use Ratchet'ConnectionInterface;
class ws implements MessageComponentInterface {
    protected $clients;
    protected $clientids;
    public function __construct() {
        $this->clients = new 'SplObjectStorage; 
        $this->clientids = array();
    }
    public function multicast($msg) {
        foreach ($this->clients as $client) $client->send($msg);
    }
    public function send_to($to,$msg) {
        if (array_key_exists($to, $this->clientids)) $this->clientids[$to]->send($msg);
    }
    public function onOpen(ConnectionInterface $conn) {
        $socket_name = "{$conn->resourceId}@{$conn->WebSocket->request->getHeader('X-Forwarded-For')}";
        $this->clients->attach($conn,$socket_name);
        $this->clientids[$socket_name] = $conn;
    }
    public function onMessage(ConnectionInterface $from, $msg) {
    }
    public function onClose(ConnectionInterface $conn) {
        unset($this->clientids[$this->clients[$conn]]);
        $this->clients->detach($conn);
    }
    public function onError(ConnectionInterface $conn, 'Exception $e) {
        $conn->close();
    }
}

这添加了两个函数,一个用于多播,另一个用于通过字符串ID socket_name向客户端发送消息(我选择了socketid和ip的组合来阻止可能的冲突)。

因此发送到客户端:

$ws->send_to(socket_name,message);

很明显,$ws是在启动时创建的websocket:

$ws = new mine'ws();
$ws_server = new Ratchet'Server'IoServer( new Ratchet'Http'HttpServer( new Ratchet'WebSocket'WsServer( $ws ) ), $socket );
相关文章:
  • 没有找到相关文章