Location: PHPKode > scripts > setTimeout and setInterval > settimeout-and-setinterval/Timers.class.php
<?php
/**
 *	************************ NOTICE ***********************************
 *
 *		The use of Timers WILL slow down your script execution time.
 *		By how much is determined by the user implementation.
 *
 *	*******************************************************************
 *
 *	This pacakge contains one class for handling timers in PHP
 *	and enables the handling of callback functions at given intervals
 *	in microseconds (NOT milliseconds like javascript), as well as 
 *	removing said functions from the stack of callable functions.
 *	
 *	The class is dependent on the PHP language construct declare(ticks=N);
 *	where N represents how many "tickable statements" that get processed
 *	before a registered tick function is called and MUST be declared in the top level script, 
 *	not an included file in order to be effective. 
 *
 *	@see http://us.php.net/manual/en/control-structures.declare.php#control-structures.declare.ticks
 *	
 *	The value of N determines
 *	1) how close to perfect accuracy the timers are (probably never be perfect though)
 *	2) how fast the script will be processed
 *	If N == 1 the script will be very close to perfectly accurate, but will run very slow
 *	but if N is set TOO high (like 10000) it may not be very effective or accurate.
 *	It is up to the user to determine what this number should be for their script.
 *
 *	The package also includes 4 functions for simplifying calls to the static methods of the class:
 *		-- setTimeout, setInterval, clearTimeout, clearInterval
 *
 *	@author Sam Shull <hide@address.com>
 *	@version 0.5
 *
 *	07/19/2009
 *	@copyright Copyright (c) 2009 Sam Shull <hide@address.com>
 *	@license <http://www.opensource.org/licenses/mit-license.html>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *	
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *	
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 *	
 *
 *	<code>
 *		require_once 'Timers.class.php';
 *
 *		$timer = setTimeout('print "\ntimeout";', 1000);
 *
 *		//this is the part that makes the timers work, 
 *		///but also slows the script down
 *		declare(ticks=1);
 *
 *		//do something else
 *	</code>
 *
 *	Changes - 
 *			07/20/2009 - added Timers::microtime
 */

/**
 *	Just for simplifying the Timers::setTimeout method
 *
 *
 *	@param callable | string $func
 *	@param integer $microseconds - remember this is microseconds NOT milliseconds
 *
 *	@return integer
 */
function setTimeout ($func, $microseconds)
{
	return Timers::setTimeout($func, $microseconds);
}

/**
 *	Just for simplifying the Timers::setInterval method
 *
 *
 *	@param callable | string $func
 *	@param integer $microseconds - remember this is microseconds NOT milliseconds
 *
 *	@return integer
 */
function setInterval ($func, $microseconds)
{
	return Timers::setInterval($func, $microseconds);
}

/**
 *	Just for simplifying the Timers::clearTimeout method
 *
 *
 *	@param integer $interval - an integer representing the one returned from a call to setTimeout()
 *
 *	@return boolean
 */
function clearTimeout ($func, $microseconds)
{
	return Timers::setTimeout($func, $microseconds);
}

/**
 *	Just for simplifying the Timers::clearInterval method
 *
 *
 *	@param integer $interval - an integer representing the one returned from a call to setInterval()
 *
 *	@return boolean
 */
function clearInterval ($interval)
{
	return Timers::clearInterval($interval);
}

/**
 *	This class contains a series of static properties and functions
 *	that enable the creation and execution of timers
 *
 *	@author Sam Shull
 */
class Timers
{
	/**
	 *	An array of the arrays that represent
	 *	the timer information used by Timers::tick
	 *
	 *	@access private
	 *	@staticvar array
	 */
	private static $timers = array();
	
	/**
	 *	Tracker of timers
	 *
	 *
	 *	@access private
	 *	@staticvar integer
	 */
	private static $numTimers = 0;
	
	/**
	 *	An array of the arrays that represent
	 *	the interval information used by Timers::tick
	 *
	 *	@access private
	 *	@staticvar array
	 */
	private static $intervals = array();
	
	/**
	 *	Tracker of intervals
	 *
	 *
	 *	@access private
	 *	@staticvar integer
	 */
	private static $numIntervals = 0;
	
	/**
	 *	Used for debugging
	 *
	 *
	 *	@access private
	 *	@staticvar integer
	 */
	//private static $ticks = 0;
	
	/**
	 *	A utility method called after N number of ticks by the engine
	 *	that checks each timer and interval to see if the desired 
	 *	number of microseconds have passed and executes the function 
	 *	when appropriate
	 *
	 *	@static
	 *	@return void
	 */
	public static function tick ()
	{
		//++self::$ticks;
		
		$time = self::microtime();
		
		foreach (self::$timers as $position => $timer)
		{
			if ($time >= $timer['time'])
			{
				call_user_func($timer['function']);
				unset(self::$timers[$position]);
			}
		}
		
		foreach (self::$intervals as $position => $timer)
		{
			if ($time >= $timer['time'])
			{
				call_user_func($timer['function']);
				self::$intervals[$position]['time'] = self::microtime() + self::$intervals[$position]['microseconds'];
			}
		}
	}
	
	/**
	 *	A utility method for retrieving the most accurate
	 *	microtime available
	 *
	 *	@static
	 *	@return float
	 */
	public static function microtime ()
	{
		list($m, $s) = explode(' ', microtime());
		return round(((float)$m + (float)$s) * 1000000);
	}
	
	/**
	 *	A utility method that ensures that all the timeouts have been called
	 *	and that calls all the intervals one more time
	 *
	 *
	 *	@static
	 *	@return void
	 */
	public static function shutdown ()
	{
		foreach (self::$timers as $position => $timer)
		{
			call_user_func($timer['function']);
			unset(self::$timers[$position]);
		}
		
		foreach (self::$intervals as $position => $interval)
		{
			call_user_func($interval['function']);
			unset(self::$intervals[$position]);
		}
		
		//print "\nticks: " . self::$ticks;
	}
	
	/**
	 *	Add a function to the be executed after ($microseconds) microsecond
	 *
	 *	@static
	 *
	 *	@param callable | string $func
	 *	@param integer $microseconds - remember microseconds, not miliseconds
	 *
	 *	@return integer
	 */
	public static function setTimeout ($func, $microseconds)
	{
		if (!is_callable($func))
		{
			if (is_string($func))
			{
				$func = create_function('', $func);
			}
			else
			{
				throw new InvalidArgumentException();
			}
		}
		
		self::$timers[++self::$numTimers] = array(
													'time' => self::microtime() + $microseconds, 
													'function' => $func,
												);
		
		return self::$numTimers;
	}
	
	/**
	 *	Add a function to the be executed every ($microseconds) microsecond
	 *
	 *	@static
	 *
	 *	@param callable | string $func
	 *	@param integer $microseconds - remember microseconds, not miliseconds
	 *
	 *	@return integer
	 */
	public static function setInterval ($func, $microseconds)
	{
		if (!is_callable($func))
		{
			if (is_string($func))
			{
				$func = create_function('', $func);
			}
			else
			{
				throw new InvalidArgumentException();
			}
		}
		
		self::$intervals[++self::$numIntervals] = array(
															'time' => self::microtime() + $microseconds, 
															'function' => $func,
															'microseconds' => $microseconds,
														);
		
		return self::$numIntervals;
	}
	
	/**
	 *	Remove a timeout function from the stack
	 *
	 *	@static
	 *
	 *	@param integer $timer
	 *
	 *	@return boolean
	 */
	public static function clearTimeout ($timer)
	{
		if (isset(self::$timers[$timer]))
		{
			unset(self::$timers[$timer]);
			return true;
		}
		
		return false;
	}
	
	/**
	 *	Remove an interval function from the stack
	 *
	 *	@static
	 *
	 *	@param integer $interval
	 *
	 *	@return boolean
	 */
	public static function clearInterval ($interval)
	{
		if (isset(self::$intervals[$interval]))
		{
			unset(self::$intervals[$interval]);
			return true;
		}
		
		return false;
	}
}

/**
 *	Register these methods in order to perform polling a specific intervals
 *	that are set by the user
 */
register_tick_function(array('Timers','tick'));
register_shutdown_function(array('Timers','shutdown'));

?>
Return current item: setTimeout and setInterval