Php 按附加信息查找SplObjectStorage中的对象
我使用PHP Ratchet构建了一个聊天应用程序 我将所有连接存储在SplObjectStorage中 每个连接都将具有用户id,我将通过以下方式将其附加:Php 按附加信息查找SplObjectStorage中的对象,php,Php,我使用PHP Ratchet构建了一个聊天应用程序 我将所有连接存储在SplObjectStorage中 每个连接都将具有用户id,我将通过以下方式将其附加: public function __construct() { $this->clients = new \SplObjectStorage; } public function onOpen(ConnectionInterface $conn) { // Store t
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");
我想知道是否有更快的方法。也许可以使用如下功能:
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)
}
*/
另一个选项是,基于父函数构建一个信息对象映射。这有点复杂:
<?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();
}
}
这增加了两个函数,一个用于多播,另一个用于通过socket_名称向客户端发送消息,socket_名称是一个字符串ID(我选择了socket ID和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 );