Skip to content
This repository has been archived by the owner. It is now read-only.
Simple Javascript like timer implementation for PHP
PHP
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
README.md
composer.json
test.php

README.md

PHP Timer

This is simple Javascript like timer implementation for PHP. It's not meant to be a production library so don't use it.

Functions:

  • setTimeout(callable $callback, int $milliseconds): int - schedules a timer and returns its ID
  • setInterval(callable $callback, int $milliseconds): int - schedules a periodic timer and returns its ID
  • clearTimeout(int $id): void - aborts a timer
  • clearInterval(int $id): void - aborts an interval

Original solution by Jakub Vrána found years ago here; this one is different, since I don't think the proposed code works the same way the Javascript does.

There is an important thing you might not notice in Javascript. Whenever you set a timer, remaining time is not being updated while a synchronous, blocking code is running. Since almost all the API Javascript has is asynchronous, it's not an issue.

Take a look at this code:

setTimeout(function() {
    print 'Hello ';
}, 0);

sleep(1);
print 'World!';

At first look, it seems like Hello should print first (time set to 0 ms) and World! should follow a second later. Instead, this is what actually happens:

  1. our Hello callback gets queued with time set to 0 ms,
  2. sleep(1) hangs the execution for a second - that's because it's synchronous and blocking,
  3. World! gets printed, because everything behind the initial setTimeout is still a synchronous code,
  4. now, our internal event loop takes the timer with least remaining time (waits eventually) and executes it.

This is in fact exactly the same thing Javascript does. It doesn't have a sleep() function, but here is how you could emulate it:

setTimeout(() => console.log('Hello '), 0);

alert('Read this for a second and then close it.');
console.log('World!');

You can run this code in your browser and see what happens - just like in PHP, World! will be printed first and Hello will follow right after closing the alert window.

Solution

The thing we can realize here is that Javascript event loop doesn't have any sort of interruption nor threading and it doesn't measure remaining time by abusing OS current time. Instead, it sleeps till a timer is ready when there's no synchronous code being executed. Synchronous code execution simply delays all pending timers.

Therefore, this is why I think my implementation is as close to Javascript behavior as it can be.

As shown above, the correct (well, Javascript) solution doesn't use microtime(), ticks nor threads. Whenever a timer is set, we'll store the user defined time (*1000 - we'll need microseconds instead of milliseconds for usleep() later) and set its remaining time the same.

Now, we'll run our event loop on shutdown using register_shutdown_function() and till a timer exists, we will repeat this:

  1. obtain a timer with least remaining time,
  2. usleep() on remaining time,
  3. decrease other timers remaining time by the remaining time of currently executed timer,
  4. execute the current timer (reset its remaining time if it's periodic, drop otherwise).

Note that since we're calling usleep() here, timing accuracy suffers. That's actually another con for microtime() - if we would decrease remaining time by something measured using this function, timers with low fractions of seconds might be executed in an unexpected order, which is a serious issue we're trying to mitigate by maintaining the remaining time manually, using exactly calculated microseconds. This applies for Javascript as well - timers are guaranteed to be executed in an expected order, not in an accurate expected time.

You can’t perform that action at this time.