PHP Classes

File: class.nb_cli_1.0.php

Recommend this page to a friend!
  Classes of JImmy Bo   PHP Non Blocking CLI   class.nb_cli_1.0.php   Download  
File: class.nb_cli_1.0.php
Role: Class source
Content type: text/plain
Description: PHP NonBlocking CLI - Plugin based non-blocking CLI class for PHP console programs
Class: PHP Non Blocking CLI
Implement CLI scripts that do not block the output
Author: By
Last change: comments
Date: 11 months ago
Size: 10,893 bytes
 

Contents

Class file image Download
<?php /* class: PHP NonBlocking CLI - Plugin based non-blocking CLI class for PHP console programs version: 1.0 url: https://www.phpclasses.org/package/12994-PHP-A-non-blocking-CLI-class-for-PHP-console-programs.html author: https://www.phpclasses.org/browse/author/144301.html license: BSD License (3-clause BSD) https://opensource.org/licenses/BSD-3-Clause nb_cli: main controller class nb_plugin: abstract class for plugins (You would then extend this class to make your own plugins for nb_cli) short description: A non-blocking CLI class for PHP console programs. long description: This class allows for non-blocking CLI input and output using plugins to contain the external functionality. The main loop runs at a set speed, and each plugin can run at its own speed (but within the speed of the main loop). The main controller can interact with the user. The plugins can also interact with the user, and are intended to be the primary interaction with the user. Plugins are only aware of themselves, and have no knowledge of other plugins, or the main controller. note: THIS CLASS IS INTENDED FOR COMMAND LINE RUN PHP. Run an example from the command line to see it in action. eg) php test-cli.example.php eg) php test-cli.example.game.php example ideas for programs that could potentially benefit from this class: - a MUD (multi-user dungeon) game - realtime text based rpg game - game engine - interactive server apps - etc... quick example: // --- // step 1: create a plugin class my_plugin extends nb_plugin { private $stdin; private $stdout; // handler for running multiple loops at different intervals // // so we can give this plugin some loop independence (run on their own timers) private $next_run = []; // when a loop should run // An array so we can have multiple loops. private $loop_running = []; // so we don't engage another loop until the other is finished processing public function __construct() { // Set non-blocking mode for STDOUT stream_set_blocking(STDOUT, false); // Set non-blocking mode for STDIN stream_set_blocking(STDIN, false); $this->stdin = fopen('php://stdin', 'r'); $this->stdout = fopen('php://stdout', 'w'); } public function out($msg) { fwrite($this->stdout, $msg); } public function handleCommand($command) { // handle incoming commands switch ($command) { case 'test': $this->out("Test command\n"); break; } } public function welcome() { // welcome message $this->out("-- NonBlockingCLI test server --\n"); $this->out("Welcome to the NonBlockingCLI test server.\n"); } public function run() { // called every loop $this->loop_1(); $this->loop_2(); } private function loop_1() { // This value will be used to set the pace of this loop. $loop_timer = 3.0; // seconds // how often to run this loop // 1.0 = 1 second, 1.5 = 1.5 seconds, etc. // set a key for this loop to store its timing values like next_run and loop_running $loop_key = 1; // for $this->next_run and $this->loop_running // we want to take a slot in next_run in case we have other loops. if (!isset($this->next_run[$loop_key])) { $this->next_run[$loop_key] = 0.0; // initialize $this->loop_running[$loop_key] = false; } // check if we should run this time if ($this->loop_running[$loop_key] || microtime(true) < $this->next_run[$loop_key]) return; // set loop as running $this->loop_running[$loop_key] = true; // BEGIN --> do stuff $output = "Current time: " . date('Y-m-d H:i:s') . "\n"; $this->out($output); // END --> do stuff // set pace of plugin loop (runs independent of main loop) // store our next run time in a variable $this->next_run[$loop_key] = microtime(true) + $loop_timer; // 1 second = 1.0, 1.5 seconds = 1.5, etc. // set loop as not running $this->loop_running[$loop_key] = false; } private function loop_2() { // This value will be used to set the pace of this loop. $loop_timer = 5.0; // seconds // how often to run this loop // 1.0 = 1 second, 1.5 = 1.5 seconds, etc. // set a key for this loop to store its timing values like next_run and loop_running $loop_key = 2; // for $this->next_run and $this->loop_running // we want to take a slot in next_run in case we have other loops. if (!isset($this->next_run[$loop_key])) { $this->next_run[$loop_key] = 0.0; // initialize $this->loop_running[$loop_key] = false; } // check if we should run this time if ($this->loop_running[$loop_key] || microtime(true) < $this->next_run[$loop_key]) return; // set loop as running $this->loop_running[$loop_key] = true; // BEGIN --> do stuff $output = "Tick\n"; $this->out($output); // END --> do stuff // set pace of plugin loop (runs independent of main loop) // store our next run time in a variable $this->next_run[$loop_key] = microtime(true) + $loop_timer; // 1 second = 1.0, 1.5 seconds = 1.5, etc. // set loop as not running $this->loop_running[$loop_key] = false; } } // --- // step 2: create main controller // create main controller $cli = new nb_cli(); // step 3: add plugin to main controller $plugin = new my_plugin(); // add plugin to main controller $cli->add_plugin($plugin); // step 4: run main controller welcome() after setting up plugins // welcome message $cli->welcome(); // step 5: run main controller run() which starts main loop // optional: set speed of main loop $cli->looptime = 100000; // microseconds between loops. 100000 = 0.1 seconds // run main loop which runs until user types 'quit'. Runs plugin loops as well. $cli->run(); */ # when we make a plugin, we have to make sure it contains these functions: abstract class nb_plugin { // help: abstract class makes sure that all plugins have these functions abstract public function handleCommand($command); // handle incoming commands abstract public function welcome(); // abstract public function run(); // called every loop } // this class is the main controller that passes messages to the plugins. class nb_cli { private $stdin; private $stdout; // main loop speed public $looptime = 100000; // microseconds between loops. 100000 = 0.1 seconds // plugins private $plugins = array(); public function __construct() { // Set non-blocking mode for STDOUT stream_set_blocking(STDOUT, false); // Set non-blocking mode for STDIN stream_set_blocking(STDIN, false); // ability for main loop to interact with user $this->stdin = fopen('php://stdin', 'r'); $this->stdout = fopen('php://stdout', 'w'); } public function out($msg) { fwrite($this->stdout, $msg); } public function add_plugin(nb_plugin $plugin) { $this->plugins[] = $plugin; } public function welcome() { // process plugins foreach ($this->plugins as $plugin) { $plugin->welcome(); } } public function run() { while (true) { // Process user commands for main loop if (($command = fgets($this->stdin)) !== false) { $command = trim($command); $this->handleCommand($command); } // Process plugins foreach ($this->plugins as $plugin) { $plugin->run(); } // Sleep for a while usleep($this->looptime); // main loop runs every 100000 microseconds = 0.1 seconds } } private function handleCommand($command) { // pass command to plugins foreach ($this->plugins as $plugin) { $plugin->handleCommand($command); } // basically main loop just handling a 'quit' command switch ($command) { case 'quit': exit(); break; } } } ?>