Plus is just an asynchronous event-loop for handling I/O events & network sockets in pure PHP, You can now comparePHP 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\nHello
");
});
$client->on("drain", function($client){
$client->close();
});
$client->on('error', function($e, $client){
$client->close();
});
});
$server->listen(8080);
$app->run();
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";
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');
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);
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();
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);
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);
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);
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\nHello 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);
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();
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();