Jump to content

Recommended Posts

I have a class for streaming text.  My question has nothing to do with this particular, but how to modify an object.  Originally, I had functionality to deal JSON, but decided to remove that functionality as I felt it didn't belong there.  The class now looks like the following:

<?php
namespace Server;

use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
use React\Stream\DuplexStreamInterface;

class LengthPrefixStream implements EventEmitterInterface {
    use EventEmitterTrait;

    private $socket=false,
    $buffer='';

    public function __construct(DuplexStreamInterface $socket){
        $this->socket = $socket;
        $this->socket->on('data', function($data){
            $this->buffer .= $data;
            $this->parseBuffer();
        });
    }

    public function send($message){
        //Still need to implement drain
        if($this->isConnected()) {
            $this->socket->write(pack("V", strlen($message)).$message);
            return true;
        }
        else {
            return false;
        }
    }

    private function parseBuffer(){
        do {
            $checkAgain = false;
            $bufferLength = strlen($this->buffer);
            $length = unpack('Vlen', substr($this->buffer, 0, 4))['len'];
            if($bufferLength >= $length + 4){
                $this->emit('data', [substr($this->buffer, 4, $length)]);
                $this->buffer = substr($this->buffer, $length+4);
                $checkAgain = strlen($this->buffer)>=4;
            } 
        } while ($checkAgain);
    }

    public function isConnected()
    {
        return $this->socket?true:false;
    }

    public function close()
    {
        $this->socket->close();
    }
}

I use it something like this:

    protected function sendCommand($text)
    {
        $data = false;
        $loop = new \React\EventLoop\StreamSelectLoop();
        $socket = new \React\SocketClient\TimeoutConnector(new \React\SocketClient\TcpConnector($loop), 15, $loop);
        $socket->create($this->host['url'], $this->host['port'])->then(function($stream) use (&$data, $loop, $text){
            $client = new \DataLogger\Server\LengthPrefixStream($stream);
            $client->on('data', function($data) use (&$data, $loop, $stream){
                //Passed by reference $data will be set.  Maybe need to use a separate variable?
                $stream->close();
                $loop->stop();
            });
            $client->send($text);
        });
        $loop->run();
        return $data;   //False on failure
    }

But now I wish to send and return variables other than text, and will need to convert them to JSON.

 

I still don't wish to put this functionality in the class.  Furthermore, I use this class more than one place, so don't wish to duplicate the JSON conversion and checking that it is valid JSON each time.

 

I am thinking I might be able to wrap the object in another method.

//$client = new \DataLogger\Server\LengthPrefixStream($stream);
$client = $this->wrapClient(new \DataLogger\Server\LengthPrefixStream($stream));
protected function wrapClient($client)
{
    /*
    Turn messages sent into JSON and verify that it is valid.
    Turn responses received into JSON and verify that it is valid.
    */
}

But I am kind of at a lose where to go next.

 

Any suggestions?

Link to comment
https://forums.phpfreaks.com/topic/303399-wrapping-an-object-in-a-method/
Share on other sites

Or maybe I should be wrapping it not in a method, but another class?  The send() method seems okay, but not the on() method.
 
The reason I tried to get away from having the json scope in the LengthPrefixStream class is I wish to log json errors, and didn't want to pass a logger into a generic class.  Guess I will need to do the same if I use this approach...
$client = new wrapClient(new \DataLogger\Server\LengthPrefixStream($stream));
class wrapClient
{
    public function __construct($client){
        $this->client = $client;
    } 
    public function send($msg)
    {
        $this->client->send(json_encode($msg));
    }

    public function on($msg)
    {
        $o = json_decode($msg);
        if (json_last_error() != JSON_ERROR_NONE){
            $rsp='ERROR: Invalid JSON provided';
        }
        return o;
    }
}

 

Your wrapping class sounds more or less like my JSONStream class from an earlier example.

 

Almost...  Yours worked!

 

Maybe I put the on method in the constructor like you did.

 

Or maybe I just go back to putting this json functionality in the class like you did, and pass back some message if json isn't valid.

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.