phpwebsocketratchet

Is it possible to store additional variables in a ratchet connection


this is my onMessage

public function onMessage(ConnectionInterface $from, $msg) {
    $tempMessage = json_decode($msg, TRUE);
    if ($tempMessage['type'] == 'online') {
        foreach ($this->clients as $client) {
            if ($client == $from) {
                echo "client " . $from->resourceId . "(" . $from->remoteAddress . ") is online\n";
            }
        }
    }

}

Is it possible to save values in this $client object for later reference?

i know it is possible to keep a array for this but it can get complicated as in the documentation im storing the clients in a SplObjectStorage


Solution

  • The Generic way

    If you have a look at the php documentation for \SplObjectStorage you will see that you can add information to an object, so according to your code you can add the data like this

    $this->clients[$from]->setInfo(['myData' => 'foo']);
    

    And then retrieve it like this

    $data   = $this->clients[$from]->getInfo();
    var_dump($data); // $data = ['myData' => 'foo']
    

    The Easy/Fast way

    Disclaimer: this is only to set data in onOpen (eg: cookies), after that the connection is cloned everytime to be passed to onMessage making the original connection immutable, this is why I wouldn't recommend this solution to set data unrelated to the original connection, because it could lead to hard to debug bugs

    Since the connection is a php class you are allowed to add properties to it as long as the property is not already defined as protected or private

    In the source code of the client class (In \Ratchet\AbstractConnectionDecorator) you will find

    public function __set($name, $value) {
        $this->wrappedConn->$name = $value;
    }
    
    public function __get($name) {
        return $this->wrappedConn->$name;
    }
    

    Meaning the class is just a wrapper for a \React\Socket\Connection which has no setter/getter.

    So you can manipulate the properties like you would on an object

    $client->myData = $data;
    var_dump($client->myData);
    

    The alternative way

    Instead of storing your clients in an \SplObjectStorage store them in a keyed array and use spl_object_hash to generate the key

    PS: This is already what's happening under the hood of SplObjectStorage so this is reinventing the wheel

    /**
     * @var array[]
     */
    protected $clients = [];
    
    public function onOpen( ConnectionInterface $conn ) {
        $this->clients[spl_object_hash( $conn )] = [ 'connection' => $conn, 'myData' => "My data" ];
    }
    
    public function onMessage( ConnectionInterface $conn, $msg ) {
        $myData = $this->clients[spl_object_hash( $conn )]['myData'];
    }