+ $mode = getenv('TIME_FUNC') ? getenv('TIME_FUNC') : 'natural';
+
+ list ($modeName, $modeNum) = explode(":", "$mode:");
+
+ switch ($modeName) {
+ case 'frozen':
+ // Every getTime() will produce the same value (ie $newDateTime).
+ $now = strtotime($newDateTime);
+ self::$callback = function () use ($now) {
+ return $now;
+ };
+ break;
+
+ case 'natural':
+ // Time changes to $newDateTime and then proceeds naturally.
+ $delta = strtotime($newDateTime) - time();
+ self::$callback = function () use ($delta) {
+ return time() + $delta;
+ };
+ break;
+
+ case 'linear':
+ // Time changes to $newDateTime and then proceeds in fixed increments ($modeNum milliseconds).
+ $incr = ($modeNum / 1000.0);
+ $now = (float) strtotime($newDateTime) - $incr;
+ self::$callback = function () use (&$now, $incr) {
+ $now += $incr;
+ return floor($now);
+ };
+ break;
+
+ case 'prng':
+ // Time changes to $newDateTime and then proceeds using deterministic pseudorandom increments (of up to $modeNum milliseconds).
+ $seed = md5($newDateTime . chr(0) . $mode, TRUE);
+ $now = (float) strtotime($newDateTime);
+ self::$callback = function () use (&$seed, &$now, $modeNum) {
+ $mod = gmp_strval(gmp_mod(gmp_import($seed), "$modeNum"));
+ $seed = md5($seed . $now, TRUE);
+ $now = $now + ($mod / 1000.0);
+ return floor($now);
+ };
+ break;
+
+ default:
+ throw new \RuntimeException("Unrecognized TIME_FUNC ($mode)");
+ }
+