Welcome to Plus environment

Plus is just an asynchronous event-loop for handling I/O events & network sockets in pure PHP, You can now compare PHP vs NodeJS .
In another words it is the micro implementation of nodejs in pure php .


    // a very simple HTTP server in Plus environment

    include "Plus.php";

    use Plus\Frame;

    $app    =   new Frame;
    $server =   $app->ioserver();

    $server->on("connection", function($client){
        $client->on('data', function($data) use($client) {
            $client->write("HTTP/1.1 200 OK\r\nContent-Type: text/html;\r\nServer: Plus/1.0\r\n\r\n

Hello

"); }); $client->on("drain", function($client){ $client->close(); }); $client->on('error', function($e, $client){ $client->close(); }); }); $server->listen(8080); $app->run();

Prototype

Prototype is a class that extends PHP's ArrayObject and adds some features to it, lets see examples:


    require "Plus.php";

    use Plus\Prototype;

    // lets use it as a container for our vars
    $my = new Prototype;

    // assign a value to a var
    $my->key1 = "value1";

    // array style
    $my['key2'] = "value2";

    // a closure
    $my->func = function(){
        print "func";
    };

    // call the closure
    $my->func();

    // or
    $my['func']();

    // nested, 'without getting errors'
    $my->x->y->z = "Wow";
    $my->x->y->z->a->b->c->d = array();

    // export ?
    $my->toArray();

    // import ?
    $my->import(array(/*...*/));

    // you can do anything could ArrayObject do

    // lets create a class that extends it
    Class Wow extends Prototype{}
    
    // start it
    $wow = new Wow(array(
        /*
            optional param to import array/object into the wow scope
        */
    ));

    // get wow instance ?
    Wow::instance();

    // and so ...
    $wow->x = "v";

EventEmitter

A class that helps you create an event-driven apps, it is inspired by javascript EventEmitter, it also extends the Prototype Class


    require "Plus.php";

    use Plus\EventEmitter;

    // construct
    $e = new EventEmitter;

    // register a new listener
    $e->addListener('event.1', $l1 = function(){
        print "listener.1";
    });

    // you can also use this alias
    $e->on('event.1', function(){
        print "listener.2";
    });

    // you can cancel the next listeners in the event queue
    // just like javascript
    $e->on('event.1', $l2 = function(){
        print "will cancel next";
        return false; //> this is the solution
    });

    // to register a one-time listener
    // there is an argument called $once
    // the third argument will be true
    $e->on('event.1', function(){
        print "listener.3 only-once";
    }, true);

    // or use this
    $e->once('event.1', $l3 = function(){
        print "listener.4 only-once";
    });

    // to emit the event.1 listeners
    $e->emit('event.1');

    // you can also pass arguments
    // as the second the argument
    $e->emit('event.1', "arg1");
    $e->emit('event.1', array("arg1", "arg2"));

    // an example for filters
    $test = "text";

    $e->on('event.2', $l4 = function($text, $last_return){
        // last return is a param that has the value
        // of the last executed listener !
        return "{$text}";
    });

    // arg1: the event-name
    // arg2: the param to pass to the listeners
    // arg3: the default value to return if it were empty
    $text = $e->emit('event.2', $text, $text);

    // remove a registered listener from an event
    $e->removeListener('event.1', $l1);

    // remove all event-listener
    $e->removeAllListeners('event.1');

    // remove all listeners for all events
    $e->removeAllListeners();

    // set the maximum listeners per event
    // default = 0 "unlimited"
    // we will set to "10"
    $e->setMaxListeners(10);

    // get events listeners array
    $e->listeners();

    // get count of listeners in an event
    $e->listenerCount('event.1');

Console

A class that helps you writing and reading from the console window


    require "Plus.php";

    use Plus\Console;;

    // print to the stdout
    Console::log("hello world");
    Console::log("hello, %s, %s", array("world", "plus"));

    // this is just an alias of Console::log()
    Console::error("hello error");

    // a python style
    $name = Console::input("what is your name, %s ?", "please");
    Console::log("Your name is: %s", $name);

Timers

A pure php timers class, it extends Prototype class .


    require "Plus.php";

    use Plus\Timers;;

    $timers = new Timers;

    // execute the callback each 5 seconds
    // the timer object is passed as the argument
    // also it returns the timer object .
    $timer = $timers->setInterval(function($timer){
        // your code here
    }, 5);

    // remove the timer
    $timers->clearIntervals($timer);

    // register a one time callback to be executed after 5 seconds
    // also it returns the timer object and return it .
    $timer2 = $timers->setTimeout(function($timer){
        // your code here
    }, 5);

    // remove it
    $timers->clearTimeouts($timer2);

    // run the timers tick ?
    $timers->tick();

IOLoop

An asynchronous I/O event-loop library, it extends Timers class . This library will use libevent extension if it exists, else it will use the stream_select() function .


    require "Plus.php";

    use Plus\IOLoop;;

    $loop = new IOLoop;

    // register a new stream
    // here we will watch the STDIN for read events
    $loop->add(STDIN, IOLoop::READ, function($stream, $loop){
        // this is the stream handler
        // when the STDIN changes
        // $stream: holds the stream resource "STDIN"
        // $loop: the loop object
    });

    // register a stream that we will watch for writes
    $loop->add(STDOUT, IOLoop::WRITE, function($stream, $loop){ /* ... */ });

    // remove a stream from read events ?
    $loop->remove(STDIN, IOLoop::READ);

    // or remove a stream from all events
    $loop->remove(STDIN);

    // stop the loop
    $loop->stop();

    // watch the registered streams "once"
    $timeout = 5; // used in stream_select()
    $loop->watch($timeout);

    // infinity loop
    $timeout = 5; // used in stream_select() $timeout param
    $delay = 5000; // used in usleep as an idle for the loop
    $loop->run($timeout, $delay);

IOStream

A library that based on EventEmitter and holds the streams you want automatically in the specified ioloop .


    require "Plus.php";

    use Plus\IOLoop;
    use Plus\IOStream;

    // start the main loop
    $loop = new IOLoop;

    // create an asynchronous READABLE file
    $file = new IOStream($loop, fopen("file.ext", "r"), IOStream::READABLE);

    //> Stream types: "Constants"
    // IOStream::READABLE   ->  for creating a read-only stream .
    // IOStream::WRITEABLE  ->  for creating a write-only stream .
    // IOStream::DUPLEX     ->  for creating a read/write stream .

    //> Properties
    //{
        // the stream resource
        $file->stream;
    
        // the maximum buffer-size used while reading
        // default 4096
        $file->bufferSize;
    
        // the callback used in reading
        // default fread
        $file->reader;
    
        // the callback used in writing
        // default is fwrite
        $file->writer;

        // the stream id
        // returns an unique integer of the stream
        $file->id;
    //}

    //> Events
    /*{
         "error"       when there is aan error, args [$errstr, IOStream]
         "data"        when there is any data available, args[$data, IOStream]
         "end"         when the stream reaches end of data being read from readable stream, args [IOStream]
         "flush"       when the data is being flushed, args [$data, IOStream]
         "drain"       when the stream data is drained, args [IOStream]
         "close"       when the stream is being closed, args [IOStream]
    }*/

    //> methods
    //{
        // check if the current stream is readable
        $file->isReadable(); //> true
    
        // check whether the stream is writable
        $file->isWritable(); //> false
    
        // check whether the stream is duplex
        $file->isDuplex(); //> false
    
        // remove the stream [if it were readable]
        // from the ioloop read-events
        $file->pause(); //> return $this
    
        // resume the stream [if it were readable]
        // into the ioloop read-events
        $file->resume(); //> return $this
    
        // pipe the current stream to another
        // this will copy the file data to the STDOUT "asynchronous"
        $out = new IOStream($loop, STDOUT, IOStream::WRITABLE);
        $file->pipe($out)->on('end', function($file) use($out) {
            $file->close();
        }); //> return $this
    
        // unpipe or import data from another stream [only if the stream is writable]
        // $file->unpipe($src);
        // but our stream is read-only
    
        // check whether the stream is closed
        $file->closed();
    //}

    // infinity loop
    $timeout = 5; // used in stream_select() $timeout param
    $delay = 5000; // used in usleep as an idle for the loop
    $loop->run($timeout, $delay);

IOClient

A class that based on IOStream but for asynchronous socket clients programming


    require "Plus.php";

    use Plus\IOLoop;
    use Plus\IOClient;

    // start the main loop
    $loop = new IOLoop;

    // create an asynchronous READABLE/WRITABLE stream
    $php = new IOClient($loop, IOClient::DUPLEX);

    //> Stream types: "Constants"
    // IOClient::READABLE   ->  for creating a read-only stream .
    // IOClient::WRITEABLE  ->  for creating a write-only stream .
    // IOClient::DUPLEX     ->  for creating a read/write stream .

    //> Properties [the same as IOStream]

    //> Events
    /*{
         "connection"  when the connection is created successfully, args [IOClient]
         "error"       when there is aan error, args [$errstr, IOClient]
         "data"        when there is any data available, args[$data, IOClient]
         "end"         when the stream reaches end of data being read from readable stream, args [IOClient]
         "flush"       when the data is being flushed, args [$data, IOClient]
         "drain"       when the stream data is drained, args [IOClient]
         "close"       when the stream is being closed, args [IOClient]
    }*/

    // when the connection created, lets write some data
    // only when it is available for writing
    $php->on('connection', function($php){
        $php->write("GET / HTTP/1.1\r\nHost: php.net\r\n\r\n");
    });

    // when there is any response, write it to the stdout
    $php->pipe(new IOStream($loop, STDOUT, IOStream::WRITABLE));

    //> methods [thge same as IOStream] + connect($address, array $context = array())
    // connect to PHP.net site
    $context = array(); // any valid php stream context options
    $php->connect('tcp://php.net:80');

    // infinity loop
    $timeout = 5; // used in stream_select() $timeout param
    $delay = 5000; // used in usleep as an idle for the loop
    $loop->run($timeout, $delay);

IOServer

A class that based on EventEmitter but for asynchronous socket servers programming


    require "Plus.php";

    use Plus\IOLoop;
    use Plus\IOServer;

    // start the main loop
    $loop = new IOLoop;

    // create an asynchronous socket-server
    $server = new IOServer($loop);

    //> Events
    /*{
         "listening"   when the server starts listening for connections, args [IOServer]
         "connection"  when the connection is created successfully, args [IOStream]
         "error"       when there is aan error, args [$errstr, IOServer]
    }*/

    // lets create a simple HTTP Server
    // that only prints "Hello World"
    // $client: is an instance of IOStream
    $server->on("connection", function($client){
        $client->on('data', function($data) use($client) {
            $client->write("HTTP/1.1 200 OK\r\nContent-Type: text/html;\r\nServer: Plus/1.0\r\n\r\n

Hello World

"); }); $client->on("drain", function($client){ $client->close(); }); $client->on('error', function($e, $client){ $client->close(); }); }); // start listening for connections // with a context options for setting the backlog "512" $server->listen(8080, array('socket' => array('backlog' => 512))); // infinity loop $timeout = 5; // used in stream_select() $timeout param $delay = 5000; // used in usleep as an idle for the loop $loop->run($timeout, $delay);

HTTPD

A class that based on IOServer and implements a simple http daemon


    include     "Plus.php";
    use         Plus\IOLoop;
    use         Plus\HTTPD;

    $loop   =   new IOLoop;
    $httpd  =   new HTTPD($loop);

    // returns an array with key value pairs of
    // status code => status message
    $httpd->codes;

    // bind a function that handles the whole request
    // it called only when there is any data comes from the client
    // $request: the request object [descriped later]
    // $response: the response object [descriped later]
    $httpd->createServer(function($request, $response)
    {
        $response->writeHead(200, ["Content-Type" => "text/html"]);
        $response->write("<!DOCTYPE 'html'>");
        $response->write("<html>");
        $response->write("<head>");
        $response->write("<title>Welcome to Plus http daemon");
        $response->write("</head>");
        $response->write("<body>");
        $response->write("<h1>It works !!");
        $response->write("</body>");
        $response->write("</html>");
        $response->end();
    });

    //> Events:
    /*{
         "body"        when a body line is available, args[$bodyLine, IOStream]
         "listening"   when the server starts listening for connections, args [IOServer]
         "connection"  when the connection is created successfully, args [IOStream]
         "error"       when there is aan error, args [$errstr, IOServer]
    }*/

    //> $request:
    /*{
          is a prototype object, contains the following:
          1)- "Properties":
              -> headers, a prototype object contains all request headers
                         example: $request->headers->host "will get the host field"
                         all headers in lower-case
              -> method, the current request method, "GET"
              -> uri, the current request uri, "/path?query"
              -> path, the current request path, "/path/"
              -> queryRaw, the current query string, "key=value&x=y"
    }*/

    //> $response:
    /*{
          is a protoype object that contains the following:
          1)- "Properties":
              -> headersSent: whether the headers has been sent or not
          2)- "Methods":
              -> writeHead($status, array $headers): to write headers directly
                to the client, where the $status is a valid status code [200, ... etc]
                and $headers are case-sensitive headers array
              -> write($data): writes data directly to the client
              -> end(): ends the request cycle and close the connection with the client
    }*/

    $httpd->listen(80);
    $loop->run();

Frame

Just a factory for handling our main classes, it is also based on IOLoop and it will bind them to its ioloop instance .


    require "Plus.php";

    use Plus\Frame;

    $app    =   new Frame;

    //> Creating a new ioserver
    // $server = $app->ioserver();

    //> Creating a new ioclient
    // $type [IOClient::READABLE/WRITABLE/DUPLEX]
    // $client = $app->ioclient($type);

    //> Createing a new IOStream
    // $type [IOStream::READABLE/WRITABLE/DUPLEX]
    // $stream: the resource, e.g: 'STDIN'
    // $client = $app->iostream($stream, $type);

    //> Createing a new Prototype
    // $vars = $app->prototype();

    $app->run();